Как сопоставить шаблон с необязательными окружающими кавычками?

Как можно написать регулярное выражение, которое соответствует шаблону, который может содержать кавычки, но если да, то должны иметь совпадающие кавычки в начале и в конце?

"?(pattern)"?

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

"(pattern)"|(pattern)

Будет работать, но повторяется. Есть ли лучший способ сделать это, не повторяя шаблон?


person Jake    schedule 25.08.2010    source источник
comment
Какой вид регулярного выражения вы используете? .Net допускает такое соответствие скобок, но другие варианты - нет.   -  person cristobalito    schedule 25.08.2010
comment
Связанное исследование: stackoverflow.com/questions/3165755/   -  person polygenelubricants    schedule 25.08.2010


Ответы (4)


Вы можете получить решение, не повторяя его, используя обратные ссылки и условные выражения:

/^(")?(pattern)(?(1)\1|)$/

Спички:

  • шаблон
  • "шаблон"

Не совпадает:

  • "шаблон
  • шаблон"

Однако этот образец несколько сложен. Сначала он ищет необязательную цитату и помещает ее в обратную ссылку 1, если она найдена. Затем он ищет ваш узор. Затем он использует условный синтаксис, чтобы сказать: «Если обратная ссылка 1 найдена снова, сопоставить ее, иначе ничего не сопоставить». Весь шаблон привязан (что означает, что он должен отображаться сам по себе в строке) так что несовпадающие кавычки не будут захвачены (иначе pattern в pattern" будет совпадать).

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


Обновление. Гораздо более простой версией этого регулярного выражения будет /^(")?(pattern)\1$/, для которого не требуется условное выражение. Когда я тестировал это изначально, тестер, который я использовал, дал мне ложноотрицательный результат, из-за чего я отказался от него (ой!).

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

person Daniel Vandersluis    schedule 25.08.2010
comment
Aaarrg, я только начал искать условный синтаксис regex-if в книге Friedel. Вы были быстрее +1 (следующий +1 для рекурсивного шаблона ;-) - person rubber boots; 25.08.2010
comment
@rubber Когда-то я знал, как делать рекурсивные регулярные выражения, но думаю, что забыл на благо человечества;) - person Daniel Vandersluis; 25.08.2010
comment
@Daniel: Человечество, наверное, не возражало бы, если бы вы тоже забыли об условных выражениях. ^("?)pattern\1$ работает нормально. (Удаленный ответ @wuputah не сработал, потому что он не был привязан. А @Tim, притяжательные квантификаторы / атомарные группы не нужны.) - person Alan Moore; 26.08.2010
comment
@Alan, возможно, примечание в последнем абзаце должно быть более ясным, но я не предполагал, что использование условного выражения было лучшим способом сделать это. Фактически, я никогда не использовал условные выражения в производственном коде. Я просто подумал, что это будет интересный способ решить проблему. - person Daniel Vandersluis; 26.08.2010
comment
@Alan кажется, что в тестере регулярных выражений, который я использовал, есть ошибка, и он давал мне ложный отрицательный результат для ^("?)pattern\1$, что привело к тому, что я попробовал условное решение в первую очередь ... ой. - person Daniel Vandersluis; 26.08.2010
comment
Я только наполовину шутил о том, что забываю условные обозначения. Я узнал о них очень давно, но потом я начал работать в основном на Java, которая никогда не поддерживала условные выражения, и я никогда не пропускал их. Звучит как отличная идея, но почти всегда есть способ лучше. - person Alan Moore; 26.08.2010
comment
Java не поддерживает условную конструкцию. Я использую (['] ??) (шаблон) \ 1 (? = [^']) - person lunicon; 15.01.2014

Это тоже довольно просто: (".+"|.+). Убедитесь, что первое совпадение заключено в кавычки, а второе - без кавычек.

person Jonas Stensved    schedule 15.04.2020
comment
Я удивлен, почему это никому не понравилось. Это очень просто и элегантно. - person humility; 08.08.2020

В зависимости от языка, который вы используете, вы должны иметь возможность использовать обратные ссылки. Примерно так, скажем:

(["'])(pattern)\1|^(pattern)$

Таким образом, вы требуете, чтобы либо не было кавычек, либо чтобы на обоих концах использовалась ОДИНАКОВАЯ цитата.

person zigdon    schedule 25.08.2010

Это должно работать с рекурсивным регулярным выражением (которое требует больше времени для правильного выполнения). А пока: в Perl вы можете создать самомодифицирующееся регулярное выражение. Я оставлю это как академический пример ;-)

my @stuff = ( '"pattern"', 'pattern', 'pattern"', '"pattern'  );

foreach (@stuff) {
   print "$_ OK\n" if /^
                        (")?
                        \w+
                        (??{defined $1 ? '"' : ''})
                       $
                      /x
}

Результат:

"pattern" OK
pattern OK
person rubber boots    schedule 25.08.2010