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

Если я пытаюсь сопоставить строку с разделителями-кавычками с регулярным выражением, что из следующего «лучше» (где «лучше» означает и более эффективный, и с меньшей вероятностью сделать что-то неожиданное):

/"[^"]+"/ # match quote, then everything that's not a quote, then a quote

или же

/".+?"/   # match quote, then *anything* (non-greedy), then a quote

Предположим, что пустые строки (т.е. "") не являются проблемой. Мне кажется (не новичок в области регулярных выражений, но, конечно, не эксперт), что они будут эквивалентны.

Обновить: После размышлений, я думаю, что изменение+ символы для* все равно будет правильно обрабатывать пустые строки.

Ответы на вопрос(9)

Решение Вопроса

потому что номер два - плохая практика. Учтите, что разработчик, который идет за вами, хочет сопоставить строки, за которыми следует восклицательный знак. Должен ли он использовать:

"[^"]*"!

или же:

".*?"!

Разница появляется, когда у вас есть тема:

"one" "two"!

Первое регулярное выражение соответствует:

"two"!

в то время как второе регулярное выражение соответствует:

"one" "two"!

Всегда будьте как можно точнее. Используйте отрицательный класс символов, когда можете.

Другое отличие состоит в том, что [^ "] * может проходить через строки, в то время как. * Нет, если вы не используете однострочный режим. [^" \ N] * исключает также разрывы строк.

Что касается обратного отслеживания, второе регулярное выражение возвращает обратно для каждого символа в каждой строке, которой он соответствует. Если закрывающая кавычка отсутствует, оба регулярных выражения будут возвращаться по всему файлу. Различается только порядок, в котором затем происходит возврат. Таким образом, в теории, первое регулярное выражение быстрее. На практике вы не заметите разницу.

 Graeme Perrow18 дек. 2008 г., 21:24
Этот контрпример - именно то, что я искал, когда писал вопрос. Спасибо Ян

но он обрабатывает экранированные кавычки, а также экранированные обратные косые черты (экранированные обратные косые черты, сопровождаемые кавычками, не проблема)

/(["'])((\\{2})*|(.*?[^\\](\\{2})*))\1/

Примеры:
  "Привет, мир" Матчи"Привет, мир"
  "Привет, мир" Матчи"Привет\\"

когда граничный символ (в вашем примере двойные кавычки) присутствует в другом месте ввода.

Ваш пример № 1:

/"[^"]+"/ # match quote, then everything that's not a quote, then a quote

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

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

Я бы предложил:

([\"'])(?:\\\1|.)*?\1

Но только потому, что он обрабатывает экранированные символы кавычек и допускает использование символов 'и' в качестве символа кавычек. Я также предложил бы взглянуть на эту статью, в которой подробно рассматривается эта проблема:

http://blog.stevenlevithan.com/archives/match-quoted-string

Однако, если у вас нет серьезных проблем с производительностью или вы не можете быть уверены во встроенных кавычках, используйте более простые и удобочитаемые:

/".*?"/

Я должен признать, что нежадные шаблоны не являются базовым регулярным выражением 'ed' в стиле Unix, но они становятся довольно распространенными. Я до сих пор не привыкли группировать операторы вроде (?: Вещи).

 Peter Ajtai27 окт. 2012 г., 09:07
+1 за обратный реф
 Tomalak17 дек. 2008 г., 21:08
Не волнуйтесь. ;-) По сути, вы можете удалить весь этот диалог, так как он больше не имеет смысла.
 Harold Bamford17 дек. 2008 г., 18:51
В Perl они называются «Расширенные шаблоны». Проверять, выписыватьсяperldoc.perl.org/perlre.html в разделе «Расширенные паттерны» (около 1/3 пути вниз). В этом случае это просто как (материал), за исключением того, что нет захвата ($ 1 или \ 1).
 PEZ17 дек. 2008 г., 19:09
Я думаю, что это просто опечатка.
 Tomalak17 дек. 2008 г., 18:44
Что означает "(:? Материал)", о котором вы говорите? Я знаю "(?: Вещи)", но не знаю другого.
 Harold Bamford17 дек. 2008 г., 19:38
Это было. Я только сейчас исправил это. Я не понял первоначальный комментарий (я думал, что в SO была какая-то неясная ошибка). Извините за путаницу.

что второй лучше, потому что он перестает работать быстрее, когда завершается" пропал, отсутствует. Первый будет возвращаться через строку, потенциально дорогая операция. Альтернативное регулярное выражение, если вы используете Perl 5.10 будет/"[^"]++"/, Оно передает то же значение, что и версия 1, но так же быстро, как и версия 2.

 innaM17 дек. 2008 г., 17:46
Почему второй может провалиться быстрее?
 Leon Timmermans18 дек. 2008 г., 13:22
«прямое» отслеживание имеет некоторую стоимость, но примерно такое же, как класс персонажа в первом регулярном выражении. AFAIK это не должно возвращаться. *? сам, потому что он уже «вперед» отследил это, но я не знаю деталей реализации. Это должно было бы отказаться от первого "хотя: - /.
 Leon Timmermans17 дек. 2008 г., 17:48
Я добавил объяснение за несколько секунд до того, как вы спросили. Это второй не возвращается.
 Jan Goyvaerts18 дек. 2008 г., 11:47
Леон не прав насчет возврата. . *? Возвраты для каждого символа в строке, когда закрывающее «присутствует. Когда закрывающее» отсутствует, оба regexes backtrack.
 Jan Goyvaerts30 дек. 2008 г., 14:46
Термин «обратный путь» означает, что механизм регулярных выражений возвращается к предыдущему токену в регулярном выражении. Это ничего не говорит о движении вперед или назад в строке темы. В своем ответе я приведу общую теорию. Некоторые движки регулярных выражений могут иметь оптимизации для конкретных случаев.
 Leon Timmermans18 дек. 2008 г., 14:51
Я сделал быстрый тест. Они одинаковы как для совпадающих, так и для несопоставимых строк в Perl 5.8, но в Perl 5.10 вторая примерно в 3 раза быстрее для соответствующих строк. Что я не понимаю, так это то, что несоответствие значительно быстрее: - /.
 Leon Timmermans17 дек. 2008 г., 18:06
Если вы хотите получить действительно модные и поддержать экранированные кавычки в регулярном выражении, вы можете сделать это: / "(?: [^"] | (? <! \) (?> \\\) * \\ ") ++ «/. Я объяснил это вstackoverflow.com/questions/56554/...
 Tomalak17 дек. 2008 г., 20:37
Хороший вопрос относительно возврата. Для моего примера с "длинным циклом" это, несомненно, вызовет больший вред, чем ленивый квантификатор. Также хорошо, что вы упомянули собственнические квантификаторы. +1

*?" вещь до сегодняшнего дня, и я использую регулярные выражения более 20 лет, я бы проголосовал за первое. Это, безусловно, проясняет, что вы пытаетесь сделать - вы пытаетесь сопоставить строку, которая не содержит кавычек.

 Tomalak17 дек. 2008 г., 18:39
Единственное ограничение в вашем движке регулярных выражений. Существует удаленная вероятность того, что вы столкнулись с тем, который не поддерживает не жадные квантификаторы. Современные, как правило, делают.
 Jan Goyvaerts19 дек. 2008 г., 01:17
PEZ: Я настоятельно рекомендую вам использовать /.*?/ вместо /.*/U Большинство людей узнают. *? как ленивый квантификатор или, по крайней мере, как нечто, чего они не знают. A / U, спрятанный в конце регулярного выражения, легко пропустить. Речь идет о том, чтобы ваш код читался человеком.
 PEZ17 дек. 2008 г., 19:05
Некоторые движки регулярных выражений поддерживают изменение жадности по умолчанию (заставляя. * Быть не жадным и. *? Быть жадным). В PHP вы можете использовать для этого модификатор U regex. Я использовал это при очистке HTML.
 Graeme Perrow17 дек. 2008 г., 17:46
Я тоже много лет использую регулярные выражения, и я знал, что есть способ сделать что-то не жадным образом, но не осознавал, насколько это легко до сегодняшнего дня. Вот почему я спросил - мне легче читать (теперь, когда я знаю, что это значит), есть ли причина, по которой я не должен его использовать?

но это, безусловно, вопрос вкуса.

Первый может быть более эффективным?

Search for double-quote
add double-quote to group
for each char:
    if double-quote:
        break
    add to group
add double-quote to group

Что-то более сложное, включая обратное отслеживание?

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

"[^"]*"

быстрее чем

".*?"

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

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

так как его гораздо легче читать. Но я все еще хотел бы сопоставить пустые строки, поэтому я бы использовал:

/".*?"/
 slf17 дек. 2008 г., 17:35
@ Грэм Перроу:. *? является стандартом де-факто не жадного соответствия

Ваш ответ на вопрос