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


Ответы:


361

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

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

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

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

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


6
@steve: это будет также соответствовать, неправильно, "foo\". Трюк с заглядыванием в будущее делает ?квантификатор притяжательным (даже если аромат регулярного выражения не поддерживает ?+синтаксис или атомарную группировку)
Robin

1
При использовании python возникает ошибка: sre_constants.error: не может ссылаться на открытую группу
a1an

9
Это возвращает значения, включая соответствующие кавычки. Нет ли возможности вернуть только содержимое между кавычками, как было запрошено?
Мартин Шнайдер

4
Злоупотребление взглядом как собственническим квантификатором совершенно ненужно и сбивает с толку. Просто используйте чередование:(["'])(?:\\.|[^\\])*?\1
Аран-Фей

2
как избежать пустых строк?
Викас

333

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

"(.*?)"

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

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

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

11
Это здорово, однако он не обрабатывает строки с экранированными кавычками. например,"hello \" world"
Роббыт

При использовании соответствия JavaScript это также будет соответствовать кавычкам. Он будет работать с итерацией по exec, как описано здесь: stackoverflow.com/questions/7998180/…
Kiechlus

4
@robbyt Я знаю, что уже немного поздно для ответа, но как насчет негативного взгляда? "(.*?(?<!\\))"
Матеус

4
Спасибо - это проще, если вы уверены, что не существует экранированных кавычек.
Squarecandy

Одно слово. Потрясающие !
Шива Авула

89

Я бы пошел на:

"([^"]*)"

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


1
Это также ведет себя хорошо среди различных интерпретаций регулярных выражений.
Фил Беннетт

5
Это спасло мое здравомыслие. В реализации .NET для RegEx "(. *?)" Не дает желаемого эффекта (он не действует как жадный), но "([^"] *) "имеет.
Jens Neubauer

Это лучший ответ ИМО. Спасибо
Lmao 123

28

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

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

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

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

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

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

Perl нравится:

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

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

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

ECMA скрипт:

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

POSIX расширен:

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

или просто:

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

1
Python принимает скрипт ECMA с необработанным строковым форматом, т.е. r "" "скрипт ECMA" ""
a1an

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

@ douglasg14b: Спасибо. Обратите внимание, что если вы хотите использовать его в Javascript, вам нужно всего лишь использовать буквальное обозначение /pattern/без экранирования чего-либо (вместо обозначения объекта new RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");)
Casimir et Hippolyte

@ a1an: да, но вы можете использовать версию Perl, если удалите sздесь: (?s:и если вы положили (?s)где-то в шаблоне.
Казимир и Ипполит

16

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

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

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

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

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

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

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

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

-

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


Пожалуйста, почему это работает? Я использовал, src="(.*)"но, очевидно, он выбирал все до последнего ", ваш REGEX, однако, выбрал только содержимое src =" ", но я не понял, как?
Лукас Бустаманте

Мне очень нравится этот, потому что он прост, но он не очень хорошо обрабатывает пустые или
нулевые

16

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

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

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

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

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



8

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

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

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

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

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

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

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

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

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


1
Мне нравится простота вашей схемы, однако модель Casimir et Hippolyte с точки зрения производительности выбрасывает все расширенные решения из воды. Кроме того, похоже, что ваш шаблон имеет проблемы с расширенными крайними случаями, такими как экранированная кавычка в конце предложения.
wp78de

7

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

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

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

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


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

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

К сожалению, без кавычек в качестве якорей мне пришлось добавить границу, \bкоторая не очень хорошо подходит для пробелов и несловарных символов после начальной кавычки.

Или измените исходную версию, просто добавив группу и извлекая строковую форму$2 :

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

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


наблюдение: второе регулярное выражение пропускает значение со знаком минус -, как в координатах долготы.
Crowcoder

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

Вот демонстрация того, о чем я говорю. Я ожидал, что он будет соответствовать долготе (-96,74025), но это не так.
Crowcoder

@Crowcoder Спасибо. Да, это вызвано тем, что граница слова действует как якорь и помогает избежать совпадения совпадений, но не подходит для вашего ввода. Дополнительная группа на самом деле является лучшим вариантом, как отмечено в обновленном ответе.
wp78de

6

Эта версия

  • счета за сбежавшие цитаты
  • контролирует возврат

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

Это охватывает несколько строк и, похоже, неправильно обрабатывает двойную обратную косую черту, например строку: foo 'stri \\ ng 1' bar 'string 2' и 'string 3' Debuggex Demo
miracle2k

Вы не можете использовать обратную ссылку в классе символов.
HamZa

5

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

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

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


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


1
Большое спасибо. смог заменить каждое вхождение name="value"с, name={"value"}так как регулярное выражение этого ответа возвращает icon/ valueв качестве второй группы (в отличие от принятого ответа). Найти : =\"([^\"]*?[^\"]*?)\" Заменить :={"$1"}
Palisand

Разум, объясняющий отрицательный голос? это хорошо работает в некоторых ситуациях.
Джеймс Харрингтон

Ты мне отвечаешь?
Палисанд

@Palis, и никто не понизил этот пост на днях без объяснения причин.
Джеймс Харрингтон

кажется, это единственный ответ, который находит конкретный текст внутри кавычек
Top-Master

4

Мне понравилась более обширная версия 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
string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)

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

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


Если эта первая строка является фактическим кодом Python, она собирается создать строку " foo bar" "loloo". Я подозреваю , что вы имели в виду , чтобы обернуть , что в сыром строку , как вы делали с регулярным выражением: r'"\" foo bar\" \"loloo\""'. Пожалуйста, используйте отличные возможности форматирования SO, когда это уместно. Это не просто косметика; мы буквально не можем сказать, что вы пытаетесь сказать, если вы их не используете. И добро пожаловать в Stack Overflow !
Алан Мур

спасибо за совет, алан, я новичок в этом сообществе, в следующий раз я обязательно запомню все это ... искренние извинения.
Mobman

2

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

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

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

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

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


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

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

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


1

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

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

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

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

охотник


1

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

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


1

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

0

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

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

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

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

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


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

У него также есть проблемы, чтобы поймать «Не забывай @» - он останавливается после «Дон».
Бенни Нойгебауэр,

0

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

Если вы являетесь пользователем Node, вы можете захотеть модифицированную версию принятого ответа, которая поддерживает все символы Юникода:

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

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


1
Что такое не-юникод символ? AFAIK Unicode охватывает все символы.
Тото

1
Почему вы думаете, что это вопрос JavaScript? Более того, lookbehind поддерживается не во всех браузерах, regex101 выбрасывает? The preceding token is not quantifiable
Toto

@ Toto, что я имею в виду "не поддерживает все символы Unicode". Спасибо. Хотя вопрос касается регулярных выражений в целом, я просто не хочу подчеркивать, что использование утверждений о границе слов может привести к нежелательному поведению в Javascript. И, конечно, в то время как Javascripts, как правило, для браузера, есть и Node.
Донован П
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.