RegEx: захват значений между кавычками - PullRequest
181 голосов
/ 05 октября 2008

У меня есть такое значение:

"Foo Bar" "Another Value" something else

Какое регулярное выражение возвращает значения, заключенные в кавычки (например, Foo Bar и Another Value)?

Ответы [ 19 ]

293 голосов
/ 05 октября 2008

Я с большим успехом использую следующее:

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

Он также поддерживает вложенные кавычки.

Для тех, кто хочет глубже объяснить, как это работает, вот объяснение от пользователя ephemient :

([""']) соответствует цитате; ((?=(\\?))\2.) если существует обратная косая черта, сожрать ее, и если это произойдет, сопоставить символ; *? совпадать много раз (не жадно, чтобы не съесть заключительную цитату); \1 соответствует той же цитате, которая использовалась для открытия.

278 голосов
/ 05 октября 2008

Как правило, вам нужен следующий фрагмент регулярного выражения:

"(.*?)"

Это использует не жадные *? оператор, чтобы захватить все до, но не включая следующую двойную кавычку. Затем вы используете языковой механизм для извлечения сопоставленного текста.

В Python вы можете сделать:

>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']
78 голосов
/ 05 октября 2008

Я бы пошел на:

"([^"]*)"

[^ "] является регулярным выражением для любого символа, кроме '" '
Причина, по которой я использую это для оператора, не являющегося жадным, состоит в том, что я должен продолжать искать это, просто чтобы убедиться, что я понял это правильно.

23 голосов
/ 05 апреля 2015

Давайте рассмотрим два эффективных способа работы с экранированными кавычками. Эти шаблоны не предназначены для того, чтобы быть краткими и эстетичными, но чтобы быть эффективными.

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

Содержимое между кавычками описывается с помощью развернутого цикла (вместо повторного чередования), чтобы быть более эффективным: [^"\\]*(?:\\.[^"\\]*)*

Очевидно, что для работы со строками, у которых нет сбалансированных кавычек, вы можете вместо этого использовать собственнические квантификаторы: [^"\\]*+(?:\\.[^"\\]*)*+ или обходной путь, чтобы эмулировать их, чтобы предотвратить слишком большой возврат. Вы также можете выбрать, чтобы цитируемая часть могла быть открывающей кавычкой до следующей (неэкранированной) кавычки или до конца строки. В этом случае нет необходимости использовать собственнические квантификаторы, нужно только сделать последнюю цитату необязательной.

Примечание: иногда кавычки не экранируются обратной косой чертой, а повторяются. В этом случае подшаблон содержимого выглядит так: [^"]*(?:""[^"]*)*

Шаблоны избегают использования группы захвата и обратной ссылки (я имею в виду что-то вроде (["']).....\1) и используют простое чередование, но с ["'] в начале, как фактор.

Perl как:

["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')

(обратите внимание, что (?s:...) является синтаксическим сахаром для включения режима точек / однолинейных внутри группы без захвата. Если этот синтаксис не поддерживается, вы можете легко включить этот режим для всего шаблона или заменить точка с [\s\S])

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

Сценарий ECMA:

(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')

POSIX расширен:

"[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'

или просто:

"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
11 голосов
/ 10 ноября 2017

В частности, ни один из этих ответов не приводит к регулярному выражению, в котором возвращаемое совпадение - это текст внутри кавычек, что и требуется. MA-Madden пытается, но получает только внутренний матч как захваченную группу, а не весь матч. Один из способов сделать это будет:

(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)

Примеры этого можно увидеть в этой демонстрации https://regex101.com/r/Hbj8aP/1

Ключом здесь является положительный взгляд позади в начале (?<=) и положительный взгляд в конце (?=). Смотритель смотрит за текущим символом, чтобы проверить кавычку, если он найден, то начинайте оттуда, а затем с помощью предпросмотра проверяется символ на кавычку, и если найден, останавливается на этом символе. Группа lookbehind (["']) заключена в квадратные скобки, чтобы создать группу для каждой найденной цитаты в начале, затем она используется в конце lookahead (?=\1), чтобы убедиться, что она останавливается только тогда, когда находит соответствующую цитату.

Единственное другое осложнение состоит в том, что поскольку заголовок на самом деле не использует конечную кавычку, он будет снова найден начальным lookbehind, который приводит к совпадению текста между заключительными и начальными кавычками в той же строке. Помещение границы слова в открывающей кавычке (["']\b) помогает в этом, хотя в идеале я бы хотел пройти мимо, но не думаю, что это возможно. Бит, разрешающий экранирование символов в середине, я взял прямо из ответа Адама.

10 голосов
/ 14 сентября 2016

RegEx принятого ответа возвращает значения, включая их окружающие кавычки: "Foo Bar" и "Another Value" как совпадающие.

Вот RegEx, которые возвращают только значения между кавычками (как спрашивал спрашивающий):

Только двойные кавычки (используйте значение группы захвата # 1):

"(.*?[^\\])"

Только одинарные кавычки (используйте значение группы захвата # 1):

'(.*?[^\\])'

Оба (используйте значение группы захвата № 2):

(["'])(.*?[^\\])\1

-

Вся поддержка вышла и вложенные кавычки.

8 голосов
/ 29 октября 2014

Очень поздний ответ, но нравится отвечать

(\"[\w\s]+\")

http://regex101.com/r/cB0kB8/1

6 голосов
/ 06 октября 2008

Эта версия

  • приходится на экранированные кавычки
  • управляет возвратом

    /(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
    
5 голосов
/ 10 декабря 2015

Шаблон (["'])(?:(?=(\\?))\2.)*?\1 выше выполняет свою работу, но я обеспокоен его характеристиками (это неплохо, но могло бы быть и лучше). Мой ниже, это ~ 20% быстрее.

Шаблон "(.*?)" просто неполный. Мой совет всем, кто читает это, просто НЕ ИСПОЛЬЗУЙТЕ ЕГО !!!

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

$ string = 'Как дела? Я \' хорошо, спасибо ';

Остальные такие же «хорошие», как и вышеприведенные.

Если вы действительно заботитесь о производительности и точности, начните с приведенного ниже:

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

В моих тестах оно охватывало каждую встреченную мной строку, но если вы найдете что-то, что не работает, я с удовольствием обновлю ее для вас.

Проверьте мой шаблон в онлайн-тестере регулярных выражений .

4 голосов
/ 14 мая 2018

Мне понравилось Решение Eugen Mihailescu для сопоставления содержимого между кавычками, позволяя при этом избегать кавычек. Однако я обнаружил некоторые проблемы с побегом и предложил следующее регулярное выражение, чтобы исправить их:

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

Он делает свое дело и все еще довольно прост и прост в обслуживании.

Демонстрация (с некоторыми другими тестами; не стесняйтесь использовать его и расширять его).


PS: Если вы просто хотите, чтобы содержимое содержало кавычек в полном совпадении ($0), и не боялись потери производительности, используйте:

(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)

PPS: если вы сосредоточены исключительно на эффективности, используйте решение Casimir et Hippolyte ; это хорошо.

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