ожидаемое поведение расширенного регулярного выражения posix:(()|abc)xyz
Вопрос
На моей машине OS X 10.5.8, используя функции regcomp и regexec C для сопоставления расширенного регулярного выражения "(() | abc) xyz", я нахожу соответствие для строки "abcxyz", но только со смещением 3 до смещения 6.Я ожидал, что будет сопоставлена вся строка целиком и что я увижу дополнительное соответствие для начальной части строки "abc".
Когда я пробую тот же шаблон и текст с помощью awk на том же компьютере, он показывает совпадение для всей строки, как я и ожидал.
Я ожидаю, что проблема может быть в моем ограниченном опыте работы с регулярными выражениями.Кто-нибудь может объяснить, что происходит?Допустимо ли мое регулярное выражение?Если да, то почему он не соответствует всей строке целиком?
Я понимаю, что "((abc) {0,1})xyz" можно было бы использовать в качестве альтернативы, но интересующий шаблон автоматически генерируется из другого формата шаблона, и устранение экземпляров "()" - это дополнительная работа, которой я хотел бы избежать, если это возможно.
Для справки, флаги, которые я передаю regcomp, состоят только из REG_EXTENDED .Я передаю пустой набор флагов (0) в regexec.
Решение
Тот Самый POSIX стандарт гласит:
9.4.3 . Специальные символы
Специальный символ ERE обладает особыми свойствами в определенных контекстах.Вне этих контекстов или когда им предшествует
<backslash>
, таким символом должен быть ERE, который соответствует самому специальному символу.Специальные символы расширенного регулярного выражения и контексты, в которых они должны иметь свое особое значение, следующие:
.[\(
Тот Самый
<period>
,<left-square-bracket>
,<backslash>
, и<left-parenthesis>
должно быть специальным, за исключением случаев, когда используется в выражении, заключенном в квадратные скобки (см. RE Выражение, заключенное в квадратные скобки ).Вне выражения, заключенного в квадратные скобки, a<left-parenthesis>
сразу же за этим последовал<right-parenthesis>
приводит к неопределенным результатам.
То, что вы видите, является результатом вызова неопределенного поведения - все идет своим чередом.
Если вы хотите получить надежные, переносимые результаты, вам придется исключить пустое '()
- обозначения.
Другие советы
Если вы перебираете все совпадения и не получаете [3,6) и [0,6), тогда есть ошибка. Я не уверен, какой мандат posix соответствует порядку, в котором возвращаются совпадения.
Попробуйте (abc|())xyz
- держу пари, что в обоих местах результат будет одинаковым. Я могу только предположить, что версия C пытается соответствовать xyz
везде, где может, и если это не удается, она пытается сопоставить abcxyz
везде, где это возможно (но, как вы видите, это не дает сбоя, поэтому мы никогда беспокоиться о " abc " part), тогда как awk
должен использовать собственный движок регулярных выражений, который работает так, как вы ожидаете.
Ваше регулярное выражение действительно. Я думаю, что проблема либо в том, что а) POSIX не очень ясно понимает, как должно работать регулярное выражение, либо б) <=> не использует регулярные выражения, совместимые со 100% POSIX (возможно, потому что кажется, что OS X поставляется с более оригинальной версией из <=>). Независимо от того, какая это проблема, она, вероятно, вызвана тем, что это в некотором роде крайний случай, и большинство людей не стали бы писать регулярное выражение таким образом.