Регулярное выражение для строки в кавычках с экранированием кавычек

Как получить подстроку " It's big \"problem " с помощью регулярного выражения?

s = ' function(){  return " It\'s big \"problem  ";  }';     

Как найти «Это» в строке, содержащей только «Есть»? Я бы исправил это для вас, но я не знаю, какие соглашения об одинарных кавычках / escape-кодах применяются на используемом вами языке.

Jonathan Leffler 01.11.2008 18:36

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

ridgerunner 08.10.2011 18:20

@ridgerunner: Я голосую за то, чтобы закрыть это, как вы предложили. Верно, что другой вопрос более свежий, но он также намного лучше (в основном благодаря вашему ответу).

Alan Moore 17.07.2014 02:55
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
135
4
175 493
16

Ответы 16

/(["\']).*?(?<!\\)(\\\\)*\1/is

должен работать с любой строкой в ​​кавычках

Красиво, но слишком гибко для запроса (будет соответствовать одинарным кавычкам ...). И может быть упрощен до /".*?(?<!\)"/, если я что-то не пропущу. Да, и некоторые языки (например, JavaScript), увы, не понимают выражения отрицательного просмотра назад.

PhiLho 30.10.2008 15:47

@PhiLho, простое использование одного (? <! \\) приведет к сбою при экранировании обратной косой черты в конце строки. Однако верно в отношении ретроспективного анализа в JavaScript.

Markus Jarderot 01.11.2008 11:57

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

Это верно, но эта проблема вполне доступна для регулярных выражений, и существует множество их реализаций.

Alan Moore 30.10.2008 19:45
/"(?:[^"\\]|\\.)*"/

Работает в Regex Coach и PCRE Workbench.

Пример теста на JavaScript:

    var s = ' function(){ return " Is big \\"problem\\", \\no? "; }';
    var m = s.match(/"(?:[^"\\]|\\.)*"/);
    if (m != null)
        alert(m);

Имеет смысл. Обычный английский: две кавычки, окружающие ноль или более «любого символа, кроме кавычек или обратной косой черты» или «обратной косой черты, за которой следует любой символ». Не могу поверить, что не думал об этом ...

Ajedi32 04.01.2014 02:17

Я сам отвечу. =) (?:...) - это пассивная или не захватывающая группа. Это означает, что на него нельзя ссылаться позже.

magras 02.10.2014 20:27

после долгих поисков и тестов это настоящее и единственное решение, которое я нашел для этой распространенной проблемы. Спасибо!

cancerbero 16.03.2015 23:31

Спасибо за это. Я также хотел сопоставить одинарные кавычки, поэтому в итоге я адаптировал его к этому: /(["'])(?:[^\1\\]|\\.)*?\1/

leo 03.05.2015 05:47

С var s = ' my \\"new\\" string and \"this should be matched\"'; этот подход приведет к неожиданным результатам.

Wiktor Stribiżew 25.07.2016 15:38

@ WiktorStribiżew Ваша строка не соответствует описанию: строка, содержащая часть в двойных кавычках, которая может содержать экранированные двойные кавычки. Не уверен, чего вы ожидаете ...

PhiLho 26.07.2016 14:12

Для тех, кто заинтересован, размещение "\\." в первую очередь дает лучшую производительность. Я предполагаю, что это потому, что это сначала делает дополнительный поиск обратной косой черты в "[^"\\]" избыточным. Глядя на другие ответы, такие как приведенный ниже Даррелл, дает более производительное регулярное выражение (и оно включено во многие дистрибутивы Linux в соответствии с ответом). Так что для производительности используйте \"(\\.|[^\"])*\". Расчет времени в Python 3.7 дал 1,375 миллисекунда против 1,55 миллисекунды.

Jawad 08.02.2019 14:33

@ nr5 Я не знаю Свифта. Возможно, вам нужно удвоить обратную косую черту все, если у него нет специального синтаксиса для регулярных выражений. Обычно мы делаем это в C, Java и т. д., Потому что RE - это просто строки. (Предполагая, что вы говорите о синтаксической ошибке, а не об ошибке времени выполнения, это не ясно, вы даже не даете сообщение об ошибке ...)

PhiLho 14.09.2019 12:02

Перевод: совпадение цитаты, совпадение одного символа, кроме кавычек или обратной косой черты, ИЛИ сопоставление 2 символов, если первый является обратной косой чертой, совпадение предыдущей группы ноль или более раз, совпадение цитаты.

Ray Foss 12.05.2020 21:39

Это происходит из nanorc.sample, доступного во многих дистрибутивах Linux. Используется для подсветки синтаксиса строк в стиле C.

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

С var s = ' my \\"new\\" string and \"this should be matched\"'; этот подход приведет к неожиданным результатам.

Wiktor Stribiżew 25.07.2016 15:38

c.nanorc был первым местом, куда я пошел. Не удалось заставить его работать как часть строкового литерала C до тех пор, пока он не экранировал все, как этот " \"(\\\\.|[^\\\"])*\" "

hellork 28.11.2018 12:57

Это работает с функциями egrep и re_comp / re_exec из libc.

fk0 14.01.2019 13:43
"(?:\\"|.)*?"

При чередовании \" и . пропускаются экранированные кавычки, в то время как ленивый квантификатор *? гарантирует, что вы не пройдете за конец строки в кавычках. Работает с классами .NET Framework RE

Но не получается с "\\"

Ian 12.12.2014 06:17
Это не сработает с var s = ' my \\"new\\" string and \"this should be matched\"';
Wiktor Stribiżew 25.07.2016 15:39
/"(?:(?:\\"|[^"])*)"/g это должно исправить
dave 29.05.2018 18:33

Как сообщает ePharaoh, ответ:

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

Чтобы вышеуказанное применимо к строкам в одинарных или двойных кавычках, используйте

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

Это единственный набор, который у меня работал с одной большой строкой в ​​кавычках размером 1,5 КБ, содержащей 99 экранирований. Все остальные выражения на этой странице в моем текстовом редакторе прерывались с ошибкой переполнения. Хотя большинство из них работает в браузере, о чем-то нужно помнить. Рабочий пример: jsfiddle.net/aow20y0L

Beejor 04.06.2015 06:00

См. Ответ @ MarcAndrePoulin ниже для объяснения.

shaunc 08.08.2015 00:00

Если искать с самого начала, может это сработает?

\"((\\\")|[^\\])*\"

Более обширная версия https://stackoverflow.com/a/10786066/1794894

/"([^"\\]{50,}(\\.[^"\\]*)*)"|\'[^\'\\]{50,}(\\.[^\'\\]*)*\'|“[^”\\]{50,}(\\.[^“\\]*)*”/   

Эта версия также содержит

  1. Минимальная длина предложения 50
  2. Дополнительный тип котировок (открыть и закрыть )

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

"(([^"\\]?(\\\\)?)|(\\")+)+"

В большинстве представленных здесь решений используются альтернативные пути повторения, например (A | B) *.

Вы можете столкнуться с переполнением стека при больших входных данных, поскольку некоторые компиляторы шаблонов реализуют это с помощью рекурсии.

Например, Java: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993

Что-то вроде этого: "(?:[^"\\]*(?:\\.)?)*" или тот, который предоставлен Гаем Бедфордом, уменьшит количество шагов синтаксического анализа, избегая большинства переполнений стека.

/"(?:[^"\\]++|\\.)*+"/

Взято прямо из man perlre в системе Linux с установленным Perl 5.22.0. В качестве оптимизации это регулярное выражение использует «потенциальную» форму как +, так и * для предотвращения обратного отслеживания, поскольку заранее известно, что строка без закрывающей кавычки ни в коем случае не будет соответствовать.

Он отлично работает на PCRE и не подходит для StackOverflow.

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

Объяснение:

  1. Каждая строка в кавычках начинается с Char: ";
  2. Он может содержать любое количество любых символов: .*? {Ленивое совпадение}; оканчивается не escape-символом [^\\];
  3. Оператор (2) является ленивым (!) Необязательным, поскольку строка может быть пустой (""). Итак: (.*?[^\\])??
  4. Наконец, каждая строка в кавычках заканчивается символом Char ("), но ей может предшествовать четное число пар знаков escape (\\\\)+; Жадный (!) необязательный: ((\\\\)+)?+ {Жадное сопоставление}, так как строка может быть пустой или без конечных пар!

Это не самый эффективный паттерн в мире, но идея интересная. Обратите внимание, что вы можете сократить его так: "(.*?[^\\])?(\\\\)*"

Casimir et Hippolyte 18.03.2018 00:59

вот тот, который работает с обоими "и", и вы легко добавляете другие в начале.

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

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

http://www.regular-expressions.info/backref.html

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

Seph Reed 02.11.2017 09:15
@SephReed - замена [^\1] на . эффективно изменит это регулярное выражение на ("|').*?\1, а затем оно будет соответствовать "foo\" в "foo \" bar". Тем не менее, заставить [^\1] работать действительно сложно. @ Mathiashansen - Вам будет лучше с громоздким и дорогим (?!\1). (так что все регулярное выражение, с некоторой очисткой эффективности, будет (["'])(?:\\.|(?!\1).)*+\1. + не является обязательным, если ваш движок его не поддерживает.
Adam Katz 09.01.2019 00:31

Вариант, который ранее не затрагивался:

  1. Переверните строку.
  2. Выполните сопоставление перевернутой строки.
  3. Переверните совпадающие струны в обратном порядке.

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

Допустим, у вас есть следующая строка; String \"this "should" NOT match\" and "this \"should\" match" Здесь \"this "should" NOT match\" не должен совпадать, а "should" должен совпадать. Вдобавок к этому this \"should\" match должен совпадать, а \"should\" - нет.

Сначала пример.

// The input string.
const myString = 'String \\"this "should" NOT match\\" and "this \\"should\\" match"';

// The RegExp.
const regExp = new RegExp(
    // Match close
    '([\'"])(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))' +
    '((?:' +
        // Match escaped close quote
        '(?:\\1(?=(?:[\\\\]{2})*[\\\\](?![\\\\])))|' +
        // Match everything thats not the close quote
        '(?:(?!\\1).)' +
    '){0,})' +
    // Match open
    '(\\1)(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))',
    'g'
);

// Reverse the matched strings.
matches = myString
    // Reverse the string.
    .split('').reverse().join('')
    // '"hctam "\dluohs"\ siht" dna "\hctam TON "dluohs" siht"\ gnirtS'

    // Match the quoted
    .match(regExp)
    // ['"hctam "\dluohs"\ siht"', '"dluohs"']

    // Reverse the matches
    .map(x => x.split('').reverse().join(''))
    // ['"this \"should\" match"', '"should"']

    // Re order the matches
    .reverse();
    // ['"should"', '"this \"should\" match"']

Хорошо, теперь объясним, что такое RegExp. Это регулярное выражение можно легко разбить на три части. Следующее:

# Part 1
(['"])         # Match a closing quotation mark " or '
(?!            # As long as it's not followed by
  (?:[\\]{2})* # A pair of escape characters
  [\\]         # and a single escape
  (?![\\])     # As long as that's not followed by an escape
)
# Part 2
((?:          # Match inside the quotes
(?:           # Match option 1:
  \1          # Match the closing quote
  (?=         # As long as it's followed by
    (?:\\\\)* # A pair of escape characters
    \\        # 
    (?![\\])  # As long as that's not followed by an escape
  )           # and a single escape
)|            # OR
(?:           # Match option 2:
  (?!\1).     # Any character that isn't the closing quote
)
)*)           # Match the group 0 or more times
# Part 3
(\1)           # Match an open quotation mark that is the same as the closing one
(?!            # As long as it's not followed by
  (?:[\\]{2})* # A pair of escape characters
  [\\]         # and a single escape
  (?![\\])     # As long as that's not followed by an escape
)

Вероятно, это намного яснее в форме изображения: сгенерировано с использованием Регулекс Джекса

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

Вот суть примера функции, использующей эту немного более продвинутую концепцию: https://gist.github.com/scagood/bd99371c072d49a4fee29d193252f5fc#file-matchquotes-js

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

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

 line = line.replace("\\\"","\'"); // Replace escaped quotes with something easier to handle
 line = line.replaceAll("\"([^\"]*)\"","\"x\""); // Simple is beautiful

Легче читать и, вероятно, более эффективно.

Если ваша IDE - это IntelliJ Idea, вы можете забыть обо всех этих головных болях и сохранить свое регулярное выражение в строковой переменной, и когда вы скопируете и вставите его в двойные кавычки, оно автоматически изменится на приемлемый формат регулярного выражения.

пример на Java:

String s = "\"en_usa\":[^\\,\\}]+";

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

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