Поиск нескольких строк в структурированных данных - PullRequest
0 голосов
/ 29 марта 2020

Основная проблема c: задан текстовый файл в структурированном формате (XML, JSON, CSV, ...) и набор правил в виде (path, [strings, ...]), где путь описывает, какие элементы (тег XML может встречаться несколько раз, столбец CSV может встречаться несколько раз, ...) из strcutured данных, которые необходимо искать, а strings - это список строк для поиска верните смещения, в которых были найдены совпадения.

Будет специальный код для поиска путей в соответствующем документе. Мне хорошо известно, что не существует общего решения для поиска всех полей, соответствующих выражению пути, поэтому будут выделенные парсеры для XML, CSV и т. Д.

То, что я считаю решенной проблемой, - это сбор данных. алгоритм сравнения строк сам. В зависимости от того, сколько строк ищется, и если они являются литералами или регулярными выражениями, я могу выбрать что-нибудь между простым strcmp, поиском по хеш-таблице, Aho-Corasick или полноценным механизмом регулярных выражений.

Интересно, что Каковы фактические входные данные для алгоритма поиска. Я вижу два способа go здесь.

1) Разобрать структурированные данные и создать список строк для каждого пути, в котором выполняется поиск. Затем запустите поиск для каждого из путей и каждого из струны в нем. Pro: постобработка проста, очень совпадение возвращается именно там, где и должно быть. Минусы: большинство алгоритмов имеют определенные издержки во вспомогательных структурах данных, например, таблица ha sh или автомат. Они будут продублированы для каждого пути. И во-вторых, большинство алгоритмов работают эффективно на одном длинном входе. Но у меня есть несколько коротких входов.

struct SearchRule {
    std::string path;
    std::vector<std::string> terms;
};

struct SearchInput {
    std::string path;
    std::vector<std::string_view> pathContents;
};

std::vector<Results> searchAll(std::ifstream& doc, Parser& parser, std::vector<SearchRule>& rules, SearchAlgorithm& algo)
{
    std::vector<Results> results;

    for (const auto& rule : rules) {
        algo.init(rule.terms); // build auxiliarry data structures
        SearchInput input = parser.getAllElementsForPath(doc, rule.path));
        for (const auto& pathContent : input.pathContents)
            results.push_back(algo.run(pathContent);
    }
    return results;
}

2) Просто запустите поиск по всему документу. Позже я должен проверить все совпадения, где они произошли (поэтому анализ структурированного документа происходит здесь, после поиска). Проверка, находится ли смещение совпадения внутри рассматриваемого тега XML или в правильном столбце CSV. Про и c и минусы кажутся в значительной степени противоположными по сравнению с первым подходом.

std::vector<Results> searchAll(std::ifstream& doc, Parser& parser, std::vector<SearchRule>& rules, SearchAlgorithm& algo)
{
    std::vector<std::string> allInputs;
    for (const auto& rule : rules)
        // flatten all inputs into a single vector
        allInputs.insert(std::end(allInputs), std::begin(rule.terms), std::end(rule.terms));

    algo.init(allInputs);
    std::vector<Result> tempResults = algo.run(doc); // reads whole document
    // assume result contains the path name and an offset and length for each match
    std::vector<Result> ret = std::copy_if(std::begin(tempResults), std::end(tempResults), std::back_inserter(ret),
            [parser, doc](Result result){return parser.isReallyAtPath(result, doc);}); 
}

Оба примера кода приведены только для иллюстрации и не завершены. Я хорошо знаю, что один или другой, вероятно, работают лучше в зависимости от входного документа.

У меня вопрос, если я пропускаю другой вариант, совершенно другой подход?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...