Подтвердить что ты не робот

Существует ли известный алгоритм O (nm) -time/O (1) -пространства для сопоставления имен файлов POSIX (fnmatch)?

Изменить: WHOOPS! Большое допущение я испортил определение синтаксиса шаблона ? in fnmatch и, похоже, предложил (и, возможно, решил) гораздо более сложную проблему, когда он ведет себя как .? в регулярных выражениях. Конечно, на самом деле он должен вести себя как . в регулярных выражениях (сопоставление ровно одного символа, а не нуля или одного). Это, в свою очередь, означает, что моя первоначальная работа по сокращению проблем была достаточной для решения (теперь довольно скучной) оригинальной проблемы. Однако решение более сложной проблемы довольно интересно; Я мог бы написать это когда-нибудь.

С положительной стороны это означает, что существует гораздо больший шанс, что что-то вроде факуляции иглы 2way/SMOA может быть применимо к этим шаблонам, что, в свою очередь, может привести к желаемому O(n) или даже производительность.


В заголовке вопроса пусть m - длина рисунка/иглы, а n - длина строки, сопоставляемой с ней.

Этот вопрос представляет интерес для меня, потому что все алгоритмы, которые я видел/использовали, имеют либо патологически плохую производительность, либо возможные переполнения из-за обратного отслеживания или требуемое распределение динамической памяти (например, для подхода DFA или просто избегая выполнения обратного отслеживания в стеке вызовов) и, следовательно, имеют случаи сбоя, которые также могут быть опасны, если программа использует fnmatch для предоставления/запрета доступа к каким-либо правам.

Я готов поверить, что такой алгоритм не существует для соответствия регулярных выражений, но язык шаблонов имен файлов намного проще, чем регулярные выражения. Я уже упростил проблему до такой степени, что можно предположить, что шаблон не использует символ *, и в этой модифицированной задаче вы не согласуете всю строку, но ищете вхождение шаблона в строку ( как проблема соответствия подстроки). Если вы еще больше упростите язык и удалите символ ?, язык будет состоять только из конкатенаций фиксированных строк и выражений скобок, и это можно легко сопоставить в O(mn) времени и O (1) пространстве, что, возможно, может быть улучшено до O(n), если методы факторизации иглы, используемые в поиске подстроки 2way и SMOA, могут быть расширены до таких шаблонов скобок. Однако наивно каждый ? требует испытаний с или без ?, потребляющих символ, в результате чего коэффициент времени 2^q, где q - количество символов ? в шаблоне.

Кто-нибудь знает, была ли эта проблема уже решена или есть идеи для ее решения?

Примечание. При определении пространства O (1) я использую Transdichotomous_model.

Примечание 2: Этот сайт содержит подробную информацию о алгоритмах 2way и SMOA, на которые я ссылался: http://www-igm.univ-mlv.fr/~lecroq/string/index.html

4b9b3361

Ответ 1

ОК, вот как я решил проблему.

  • Попытка сопоставить начальную часть шаблона с первым * с строкой. Если это не поможет, выручите. Если это удастся, отбросьте эту начальную часть как шаблона, так и строки; мы закончили с ними. (И если мы нажмем конец шаблона перед нажатием *, у нас есть соответствие iff, мы также достигли конца строки.)

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

  • Теперь у нас остается (возможно, пустая) последовательность подшаблонов, все из которых связаны с обеих сторон с помощью *. Мы стараемся последовательно их искать в том, что осталось от строки, беря первое соответствие для каждого и отбрасывая начало строки до конца. Если мы найдем соответствие для каждого компонента таким образом, у нас будет соответствие для всего шаблона. Если какой-либо поиск компонента завершился неудачно, весь шаблон не соответствует.

Этот алогорифм не имеет рекурсии и сохраняет только конечное количество смещений в строке/шаблоне, поэтому в трансдихотомовой модели это O (1) пространство. Шаг 1 был O (m) во времени, шаг 2 был O (n + m) во времени (или O (m), если мы предположим, что длина входной строки уже известна, но я принимаю строку C) и шаг 3 (с использованием наивного алгоритма поиска) O (nm). Таким образом, общий алгоритм равен O (nm) во времени. Возможно, можно улучшить шаг 3 как O (n), но я еще не пробовал.

Наконец, обратите внимание, что исходная сложная проблема, возможно, еще полезна для решения. Это потому, что я не учитывал многосимвольные элементы сопоставления, которые большинство людей, реализующих регулярное выражение, и такие, как правило, игнорируют, потому что они уродливы, чтобы получить право, и нет стандартного API для взаимодействия с языковой системой и получения необходимой информации для получения их. Но с учетом сказанного здесь приведен пример: предположим, что ch является многосимвольным элементом сортировки. Тогда [c[.ch.]] может потреблять 1 или 2 символа. И мы снова нуждаемся в более сложном алгоритме, который я описал в своем первоначальном ответе, который, мне кажется, нуждается в пространстве O(log m) и, возможно, несколько больше, чем O(nm) времени (в лучшем случае я предполагаю O(n²m)). На данный момент у меня нет интереса к реализации поддержки многосимвольных элементов, но это оставляет приятную открытую проблему...

Ответ 2

Вы изучали механизм регулярных выражений re2 от Russ Cox (от Google)?

Это механизм согласования регулярных выражений, основанный на детерминированных конечных автоматах, который отличается от обычных реализаций (Perl, PCRE) с использованием обратного отслеживания для моделирования недетерминированного конечного автомата. Одна из конкретных целей проекта заключалась в том, чтобы устранить описанное вами катастрофическое поведение обратной трассировки.

Он запрещает некоторые расширения Perl, такие как обратные ссылки в шаблоне поиска, но вам не нужно это для сопоставления glob.

Я не уверен, что он гарантирует O(mn) время и O(1) ограничения памяти специально, но он был достаточно хорош, чтобы запустить службу поиска кодов Google во время ее существования.

По крайней мере, должно быть здорово заглянуть внутрь и посмотреть, как это работает. Russ Cox написал три статьи о re2 - один, два, три - и re2 code с открытым исходным кодом.

Ответ 3

Изменить: WHOOPS! Большое признание я испортил определение синтаксиса шаблона ? in fnmatch и, похоже, решил гораздо более сложную задачу, когда он ведет себя как .? в регулярных выражениях. Конечно, на самом деле он должен вести себя как . в регулярных выражениях (сопоставление ровно одного символа, а не нуля или одного). Это, в свою очередь, означает, что моя первоначальная работа по сокращению проблем была достаточной для решения (теперь довольно скучной) оригинальной проблемы. Однако решение более сложной проблемы довольно интересно; Я мог бы написать это когда-нибудь.

Ниже приведено возможное решение более сложной проблемы.


Я разработал то, что кажется решением в пространстве O(log q) (где q - количество вопросительных знаков в шаблоне и, следовательно, q < m) и неопределенное, но, чем экспоненциальное время.

Прежде всего, быстрое объяснение проблемы. Сначала разбивайте шаблон на каждом *; он разлагается как исходный и конечный компонент (возможно, нулевой длины), а также ряд внутренних компонентов, фланкированных с обеих сторон a *. Это означает, что если мы определим, совпадают ли исходные/конечные компоненты, мы можем применить следующий алгоритм для внутренних совпадений: начиная с последнего компонента, поиск соответствия в строке, начинающейся с самого последнего смещения. Это оставляет максимально возможное количество символов "сена", чтобы соответствовать предыдущим компонентам; если они не все нужны, это не проблема, потому что тот факт, что вмешательство * позволяет нам позже выбросить столько, сколько необходимо, поэтому не рекомендуется попробовать "использовать больше ? меток" последнего компонента или найти более раннее его появление. Затем эту процедуру можно повторить для каждого компонента. Обратите внимание, что здесь я сильно использую тот факт, что единственным "оператором повторения" в выражении fnmatch является *, который соответствует нулю или более вхождению любого символа. Такое же сокращение не будет работать с регулярными выражениями.

С этой точки зрения я начал искать, как эффективно подойти к одному компоненту. Я разрешаю коэффициент времени n, так что это означает, что все в порядке, чтобы начать пытаться на все возможные позиции в строке, и сдаться и перейти к следующей позиции, если мы потерпим неудачу. Это общая процедура, которую мы возьмем (еще никаких боев-Муро-подобных трюков, возможно, их можно будет привезти позже).

Для данного компонента (который не содержит *, только буквенные символы, скобки, которые соответствуют точно одному символу из заданного набора, и ?), он имеет минимальную и максимальную длину, которые он мог бы сопоставить. Минимум - это длина, если вы опускаете все символы ? и выражаете скобки в виде одного символа, а максимальная длина, если вы включаете символы ?. В каждой позиции мы будем пробовать каждую возможную длину, с которой мог бы сравниться компонент шаблона. Это означает, что мы проводим испытания q+1. Для следующего объяснения предположим, что длина остается фиксированной (это самый внешний цикл, вне рекурсии, который должен быть введен). Это также фиксирует длину (в символах) строки, которую мы будем сравнивать с шаблоном в этой точке.

Теперь здесь интересная часть. Я не хочу перебирать все возможные комбинации, из которых символы ? не используются/не используются. Итератор слишком велик для хранения. Поэтому я обманываю. Я разбиваю компонент шаблона на две "половинки", L и R, где каждая содержит половину символов ?. Затем я просто перебираю все возможности того, сколько символов ? используется в L (от 0 до общего числа, которое будет использоваться на основе длины, указанной выше), а затем количество символов ? используемый в R. Это также разделяет строку, которую мы пытаемся сопоставить, с частью, которая будет сопоставлена ​​с шаблоном L и шаблоном R.

Теперь мы уменьшили проблему проверки того, соответствует ли компонент шаблона с символами q ? определенной строке фиксированной длины двум экземплярам проверки того, соответствует ли шаблон с символами q/2 ? конкретную меньшую строку фиксированной длины. Применить рекурсию. И так как каждый шаг уменьшает количество задействованных <<20 > символов, количество уровней рекурсии ограничено log q.

Ответ 4

Вы можете создать хэш обеих строк, а затем сравнить их. Хэш-расчет будет выполнен в O (m), а поиск в O (m + n)

Вы можете использовать что-то вроде этого для вычисления хэша строки, где s [i] является символом

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

Как вы сказали, это для сопоставления имен файлов, и вы не можете использовать это, когда у вас есть подстановочные знаки в строках. Удачи!

Ответ 5

Я чувствую, что это невозможно.

Хотя я не могу предоставить аргумент, предупреждающий о пуле, моя интуиция заключается в том, что вы всегда сможете создавать шаблоны, содержащие q = тета (m) ?, где необходимо, чтобы алгоритм в некоторых смысл, учитывают все возможности 2 ^ q. Для этого потребуется пространство O (q) = O (m), чтобы отслеживать, какие из возможностей вы сейчас просматриваете. Например, алгоритм NFA использует это пространство для отслеживания множества состояний, в которых он сейчас находится; метод обратной перемотки грубой силы использует пространство как стек (и для добавления оскорбления к травме, он использует O (2 ^ q) в дополнение к O (q) пространства).