it-roy-ru.com

RegEx: захват значений между кавычками

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

"Foo Bar" "Another Value" something else

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

169
deadbug

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

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

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

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

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

276
Adam

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

"(.*?)"

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

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

>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']
263
Greg Hewgill

Я бы пошел на:

"([^"]*)"

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

75
Martin York

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

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

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

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

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

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

Perl нравится:

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

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

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

скрипт ECMA:

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

расширен POSIX:

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

или просто:

"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
23
Casimir et Hippolyte

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

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

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

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

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

10
IrishDubGuy

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

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

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

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

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

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

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

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

-

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

9
MA-Maddin

Очень поздний ответ, но хотел бы ответить

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

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

8
Suganthan Madhavan Pillai

Эта версия

  • учетные записи
  • контролирует возврат

    /(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
    
6
Axeman

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

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

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

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

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

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

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

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

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

5
Eugen Mihailescu

БОЛЬШЕ ОТВЕТОВ! Вот решение, которое я использовал

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

TLDR;
заменить слово значок на то, что вы ищете в указанных цитатах и ​​вуаля!


Как это работает, он ищет ключевое слово и не заботится о том, что еще между кавычками . EG:
id="fb-icon"
id="icon-close"
id="large-icon-close"
регулярное выражение ищет знак кавычки "
Затем он ищет любую возможную группу букв, которые не "
пока не найдет icon
и любая возможная группа букв, которая не является "
Затем он ищет закрывающий "

4
James Harrington

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

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

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

Demo (с еще несколькими тестами; не стесняйтесь использовать его и расширять его).


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

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

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

4
wp78de

Мне понравилась более обширная версия Axeman, но у меня возникли некоторые проблемы (например, она не соответствовала

foo "string \\ string" bar

или же

foo "string1"   bar   "string2"

правильно, поэтому я попытался это исправить:

# opening quote
(["'])
   (
     # repeat (non-greedy, so we don't span multiple strings)
     (?:
       # anything, except not the opening quote, and not 
       # a backslash, which are handled separately.
       (?!\1)[^\\]
       |
       # consume any double backslash (unnecessary?)
       (?:\\\\)*       
       |
       # Allow backslash to escape characters
       \\.
     )*?
   )
# same character as opening quote
\1
3
miracle2k
string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)

просто попробуйте, работает как шарм !!!

\ указывает на символ пропуска

2
mobman

В отличие от ответа Адама, у меня есть простой, но сработавший ответ:

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

И просто добавьте скобки, если вы хотите получить контент в кавычках, как это:

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

Затем $1 соответствует кавычке char, а $2 соответствует строке содержимого.

1
lon

От Грега Х. я смог создать это регулярное выражение в соответствии со своими потребностями.

Мне нужно было соответствовать определенное значение, которое было квалифицировано, будучи внутри кавычек. Это должно быть полное совпадение, никакое частичное совпадение не должно вызывать попадание 

например «test» не может соответствовать «test2».

reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
    print "winning..."

Охотник

1
motoprog

Дополнительный ответ для подмножества только для кодеров Microsoft VBA один использует библиотеку Microsoft VBScript Regular Expressions 5.5, и это дает следующий код

Sub TestRegularExpression()

    Dim oRE As VBScript_RegExp_55.RegExp    '* Tools->References: Microsoft VBScript Regular Expressions 5.5
    Set oRE = New VBScript_RegExp_55.RegExp

    oRE.Pattern = """([^""]*)"""


    oRE.Global = True

    Dim sTest As String
    sTest = """Foo Bar"" ""Another Value"" something else"

    Debug.Assert oRE.test(sTest)

    Dim oMatchCol As VBScript_RegExp_55.MatchCollection
    Set oMatchCol = oRE.Execute(sTest)
    Debug.Assert oMatchCol.Count = 2

    Dim oMatch As Match
    For Each oMatch In oMatchCol
        Debug.Print oMatch.SubMatches(0)

    Next oMatch

End Sub
1
S Meaden

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

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

Где .localized - суффикс.

Пример:

print("this is something I need to return".localized + "so is this".localized + "but this is not")

Он будет захватывать "this is something I need to return".localized и "so is this".localized, но не "but this is not".

0
OffensivelyBad
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'

Это приведет к:> Foo Bar <> <> но это <

Здесь я показал результирующую строку между> <для ясности, также используя не жадную версию с этой командой sed, мы сначала выбрасываем мусор до и после этого "", а затем заменяем его на часть между "" и окружить это> <'s. 

0
amo-ej1

Для меня сработало это: 

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

Я использовал в предложении, как это:

preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);

и это работало отлично.

0
Alexandru Furculita