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

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

"Foo Bar" "Another Value" something else

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

21 ответ

Решение

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

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

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

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

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

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

"(.*?)"

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

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

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

Я бы пошел на:

"([^"]*)"

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

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

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

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

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

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

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

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

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

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

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

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

Perl нравится:

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

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

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

Скрипт ECMA:

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

POSIX расширен:

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

или просто:

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

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

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

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

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

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

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

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

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

-

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

Эта версия

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

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

Мне понравилась более обширная версия 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

Мое решение этого ниже

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

Демонстрационная ссылка: https://regex101.com/r/jlhQhV/1

Объяснение:

(["'])-> Соответствует либо или и сохраняет его в обратной ссылке, как только совпадение найдено

.*-> Жадный подход, чтобы продолжать сопоставлять все ноль или более раз, пока не встретится'или"в конце строки. После обнаружения такого состояния механизм регулярных выражений возвращается к предыдущему совпадающему символу, и здесь регулярное выражение заканчивается и переходит к следующему регулярному выражению.

\1-> Соответствует символу или строке, которые ранее были сопоставлены с первой группой захвата.

(?![^\s])-> Отрицательный просмотр вперед, чтобы убедиться, что после предыдущего совпадения не должно быть никаких символов, отличных от пробела.

string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)

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

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

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

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

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

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

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

Все ответы выше хороши.... за исключением того, что они НЕ поддерживают все символы Юникода! в сценарии ECMA (Javascript)

Если вы являетесь пользователем Node, вам может потребоваться измененная версия принятого ответа, поддерживающая все символы Unicode:

/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu

Попробуйте здесь.

Дополнительный ответ для подмножества кодеров 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

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

\"([^\"]*?[^\"]*?)\".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",

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

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

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

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

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

Например, "test" не может соответствовать "test2".

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

охотник

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

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

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

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

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

Другие вопросы по тегам