Можно ли узнать, какие входные символы соответствуют какой части регулярного выражения?

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

Скажем, меня интересуют все a, предшествующие b, и не более a перед b, поэтому это регулярное выражение: a[^a]*b. Но я не просто хочу узнать, содержит ли моя строка такую ​​часть, я хочу получить в качестве вывода a, чтобы я мог его проверить (помните, я на самом деле не имею дело с текстом).

Подводя итог: допустим, я помечаю a круглыми скобками, например так: (a)[^a]*b и запускаю его на входной строке bcadacb, затем мне нужно второе a в качестве вывода.

Или, в более общем смысле, можно ли узнать, какие символы во входной строке соответствуют какой части регулярного выражения? Как это делается в текстовых редакторах? Они хотя бы знают, где начался матч, потому что могут подсвечивать матчи. Должен ли я использовать подход с возвратом или есть более умный и менее затратный в вычислительном отношении способ?

РЕДАКТИРОВАТЬ: Правильные обратные ссылки, т.е. захват с помощью скобок и ссылки с помощью \1 и т. д., могут не потребоваться. Я знаю, что обратные ссылки вводят необходимость обратного отслеживания (или чего-то подобного) и делают проблему (IIRC) NP-сложной. Мой вопрос, по сути, таков: является ли часть захвата без обратных ссылок менее затратной в вычислительном отношении, чем правильные обратные ссылки?


person oskarkv    schedule 19.07.2012    source источник
comment
Почему вы не можете сказать (a)([^a]*)(b), а затем просмотреть каждый захват, чтобы увидеть, что происходит?   -  person Seth Robertson    schedule 19.07.2012


Ответы (2)


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

Это также можно сделать с помощью прямой симуляции NFA, дополнив списки состояний информацией о местоположении в скобках. Это можно сделать таким образом, чтобы сохранить гарантию линейного времени. См. http://swtch.com/~rsc/regexp/regexp2.html#submatch< /а>.

Ответ Тимоса находится на правильном пути, но вы не можете пометить состояния DFA, потому что состояние DFA соответствует набору возможных состояний NFA, и поэтому одно состояние DFA может представлять возможность передачи скобки (но, возможно, и что-то еще) и если окажется, что это не так, было бы неправильно зафиксировать это как факт. Вместо этого вам действительно нужно поработать над симуляцией NFA.

person Russ Cox    schedule 19.07.2012

После того, как вы создали свой DFA для сопоставления, отметьте все состояния, которые соответствуют первому состоянию после открывающей скобки в регулярном выражении. При посещении такого состояния сохраните индекс текущего входного символа, при посещении состояния, которое соответствует закрывающей скобке, также сохраните индекс. Когда вы достигнете состояния принятия, выведите два индекса. Я не уверен, что это алгоритм, используемый в текстовых редакторах, но я бы сделал именно так.

person timos    schedule 19.07.2012