Как я могу сопоставить строку, разделенную кавычками, с регулярным выражением? - PullRequest
29 голосов
/ 17 декабря 2008

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

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

или

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

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

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

Ответы [ 9 ]

35 голосов
/ 18 декабря 2008

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

"[^"]*"!

или

".*?"!

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

"one" "two"!

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

"two"!

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

"one" "two"!

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

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

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

13 голосов
/ 21 июня 2013

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

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

Примеры:
"Привет \" мир " соответствует " Привет \ "мир"
"hello \\" world " соответствует " hello \\ "

9 голосов
/ 17 декабря 2008

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

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

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

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

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

/".*?"/

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

5 голосов
/ 17 декабря 2008

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

4 голосов
/ 17 декабря 2008

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

/".*?"/
2 голосов
/ 17 декабря 2008

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

"[^"]*"

быстрее

".*?"

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

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

1 голос
/ 29 декабря 2008

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

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

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

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

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

0 голосов
/ 17 декабря 2008

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

0 голосов
/ 17 декабря 2008

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...