В двух словах
Кажется, что быстрое решение вашей проблемы - определить REGEX или FSA (конечный автомат), который распознает все возможные начала документов (допускаются ложные срабатывания, которые на самом деле не соответствуют документу). Затем вы можете очень быстро запустить его на своем входе, чтобы определить следующее место, где документ может начинаться с небольшим количеством ошибок. Это может вызвать несколько ошибочных позиций для начала документа, но они будут распознаны синтаксическим анализатором и отменены.
Таким образом, Finite State Automaton может быть именем парсера, которое вы искали. :)
Проблема
Всегда трудно понять практическую проблему, особенно когда словарь может иметь много толкований. Лес синтаксического анализа слов был придуман (afaik) для анализа без контекста (CF) неоднозначных предложений, имеющих несколько деревьев синтаксического анализа. Это может быть несколько обобщено для разбора решетки предложений или для других типов грамматики. Отсюда все ответы о Earley, GLR, Marpa и производных парсерах (есть много других), которые не были уместны в этом случае.
Но это, очевидно, не то, что вы имеете в виду. Вы хотите проанализировать уникальную строку, которая является последовательностью однозначных документов, и получить дерево синтаксического анализа для каждого , или какое-то структурированное представление, поскольку вы на самом деле не говорите, как определяется синтаксис ваших документов, откуда он стоит формальная языковая точка зрения. То, что у вас есть, - это алгоритм и таблицы, которые будут выполнять работу разбора при запуске в начале документа. Быть по сему.
Фактическая проблема заключается в том, что ваш поток документов содержит значительный мусор, который разделяет документы. И, похоже, ваша сложность состоит в том, чтобы сканировать этот мусор достаточно быстро. Ваша текущая техника заключается в том, чтобы начать с самого начала и попытаться выполнить сканирование с первого символа и переходить к перезапуску на следующем символе каждый раз, когда происходит сбой, до тех пор, пока не будет отсканирован весь документ. Затем вы повторяете, начиная с первого символа после того, как документ только что отсканирован.
Это также решение, предложенное @amon во второй части его ответа .
Это может быть не очень быстрое решение (у меня нет возможности проверить), потому что маловероятно, что код синтаксического анализатора оптимизирован для очень эффективного запуска в начале документа. При обычном использовании он делает это только один раз, так что это не горячая точка с точки зрения оптимизации. Следовательно, ваше умеренное счастье с этим решением не слишком удивительно.
Так что вам действительно нужен алгоритм, который может быстро найти начало документа, который начинается с массы мусора. И вам повезло: такие алгоритмы существуют. И я уверен, что вы это знаете: это называется поиском REGEX.
Простое решение
Что вам нужно сделать, это проанализировать спецификацию ваших документов, чтобы найти, как эти документы начинаются. Я не могу точно сказать вам, как, поскольку я не уверен, как их синтаксическая структура организована формально. Возможно, все они начинаются с какого-то слова из конечного списка, возможно, смешанного с некоторыми пунктуацией или цифрами. Это для вас, чтобы проверить.
Вам нужно определить конечный автомат (FSA) или, что то же самое, для большинства программистов регулярное выражение (REGEX), которое может распознавать первые несколько символов документа: чем больше, тем лучше, но это не обязательно должно быть очень большой (так как это может занять время и пространство). Это должно быть относительно легко сделать из спецификации ваших документов, и, вероятно, это можно сделать автоматически с помощью программы, которая читает спецификацию ваших документов.
После того, как вы создали свое регулярное выражение, вы можете запустить его в своем входном потоке, чтобы очень быстро перейти к началу вашего первого (или следующего) документа следующим образом:
Я предполагаю:
- docstart
это регулярное выражение, которое соответствует началу всех документов
- search(regex, stream)
это функция, которая ищет stream
подстроку, которая соответствует regex
. Когда он возвращается, поток сводится к своему подпотоку суффикса, начинающемуся с начала первой совпадающей подстроки, или к пустому потоку совпадение не найдено.
- parse(stream)
пытается разобрать документ с начала потока (то, что от него осталось) и возвращает дерево разбора в любом формате, или происходит сбой. Когда он возвращается, поток сводится к своему подпотоку суффикса, начиная с позиции, следующей сразу за концом проанализированного документа. Это вызывает исключение, если анализ не удался.
forest = empty_forest
search(docstart, stream)
while stream is not empty:
try:
forest = forest + parse(stream)
except
remove first character from stream
search(docstart, stream)
Обратите внимание, что удаление первого символа необходимо, чтобы при следующем поиске снова не было найдено такое же совпадение.
Конечно, сокращение потока - это изображение. Это может быть просто указатель на поток.
И последнее замечание: ваше регулярное выражение не обязательно должно быть слишком точным, если оно распознает все начала. Если он иногда распознает строку, которая не может быть началом документа (ложное срабатывание), то единственным штрафом является стоимость одного бесполезного вызова парсера.
Так что это может помочь упростить регулярное выражение, если это полезно.
О возможности более быстрого решения
Вышеупомянутое решение должно работать довольно хорошо в большинстве случаев. Однако, если у вас действительно много мусора и терабайт файла для обработки, могут быть другие алгоритмы, которые работают быстрее.
Идея основана на алгоритме поиска строк Бойера-Мура . Этот алгоритм может очень быстро найти поток для отдельной строки, поскольку он использует структурный анализ строки, чтобы пропустить чтение большей части потока, перепрыгивая фрагменты, даже не глядя на них. Это самый быстрый алгоритм поиска для одной строки.
Сложность заключается в том, что его адаптация к регулярному выражению поиска, а не к одной строке, кажется очень деликатной и может не сработать, в зависимости от особенностей рассматриваемого вами регулярного выражения. Это, в свою очередь, может зависеть от синтаксиса документов, которые вы анализируете. Но не слишком доверяйте мне в этом, так как у меня не было времени внимательно прочитать найденные документы.
Я оставляю вам один или два указателя, которые я нашел в Интернете, в том числе один, который, по-видимому, является рецензируемым исследовательским документом , но вы должны рассматривать это как более умозрительный, возможно, исследовательский, который следует рассматривать, только если у вас были серьезные проблемы с производительностью. И, вероятно, нет программы полки, которая сделает это.