Используя регулярные выражения, как эффективно сопоставлять строки между двойными кавычками со встроенными двойными кавычками?

У нас есть текст, в котором мы хотим сопоставить все строки между двойными кавычками; но внутри этих двойных кавычек могут быть указаны двойные кавычки. Пример:

"He said \"Hello\" to me for the first time"

Используя регулярные выражения, как вы подходите это эффективно?

1 ответ

Очень эффективное решение для сопоставления таких входных данных заключается в использовании normal* (special normal*)* шаблон; это имя процитировано из превосходной книги Джеффри Фридла " Освоение регулярных выражений".

В целом, этот шаблон полезен для сопоставления входных данных, состоящих из обычных записей (нормальная часть), с разделителями между ними (специальная часть).

Обратите внимание, что, как и все регулярные выражения, его следует использовать, когда нет лучшего выбора; в то время как можно использовать этот шаблон для анализа CSV-данных, например, если вы используете Java, лучше использовать OpenCSV.

Также обратите внимание, что хотя квантификаторы в имени шаблона являются звездами (т. Е. Ноль или более), вы можете изменять их в соответствии со своими потребностями.

Строки со встроенными двойными кавычками

Давайте снова возьмем приведенный выше пример; и, пожалуйста, учтите, что этот образец текста может быть где угодно в вашем вводе:

"He said \"Hello\" to me for the first time"

Как бы вы ни старались, магия "точка плюс жадные / ленивые квантификаторы" не поможет вам решить ее. Вместо этого классифицируйте ввод между кавычками как нормальный и специальный:

  • нормальный - это что угодно, кроме обратной косой черты или двойной кавычки: [^\\"];
  • special - последовательность обратной косой черты, за которой следует двойная кавычка: \\",

Подставляя это в normal* (special normal*)* шаблон, это дает следующее регулярное выражение:

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

Добавление двойных кавычек в соответствие с полным текстом дает окончательное регулярное выражение:

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

Вы заметите, что это также будет соответствовать пустым кавычкам.

Слова с разделителями тире

Здесь нам придется использовать вариант с квантификаторами, так как:

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

Для простоты мы также предположим, что разрешены только строчные буквы ASCII.

Пример ввода:

the-word-to-match

Давайте снова разложим на нормальные и специальные:

  • нормальный: строчная, буква ASCII: [a-z];
  • специальные: тире: -

Каноническая форма шаблона:

[a-z]*(-[a-z]*)*

Но как мы уже говорили:

  • мы не хотим, чтобы слова начинались с тире: первый * должен стать +;
  • при обнаружении тире после нее должна быть хотя бы одна буква: вторая * должен стать +,

Мы заканчиваем с:

[a-z]+(-[a-z]+)*

Добавляем привязки к словам для получения окончательного результата:

\b[a-z]+(-[a-z]+)*\b

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

Приведенные выше примеры ограничиваются заменой * с +, но, конечно, вы можете иметь столько вариантов, сколько пожелаете. Одним ультра классическим примером будет IP-адрес:

  • нормальный до трех цифр (\d{1,3}),
  • особая точка:(\.),
  • первый normal появляется только один раз, поэтому нет количественного показателя,
  • normal внутри (special normal*) также появляется только один раз, поэтому нет квантификатора,
  • наконец то (special normal*) часть появляется ровно три раза, поэтому {3},

Что дает выражение (украшенное якорями слова):

\b\d{1,3}(\.\d{1,3}){3}\b

Заключение

Гибкость этого шаблона делает его одним из самых полезных инструментов в вашем наборе регулярных выражений. Хотя существует много проблем, для которых не следует использовать регулярные выражения, если библиотеки существуют, в некоторых ситуациях вы должны использовать регулярные выражения. И это станет одним из ваших лучших друзей, когда вы немного потренировались в этом!

подсказки

  • Более чем вероятно, что вам не нужно (или вы хотите) захватить повторяющуюся часть ((special normal*) часть); поэтому рекомендуется использовать группу без захвата. Например, используйте "[^\\"]*(?:\\"[^\\"]*)*" для цитируемых строк. Фактически, если бы вы этого хотели, захват почти никогда не приведет к желаемым результатам в этом случае, потому что повторение группы захвата даст вам только последний захват (все предыдущие повторы будут перезаписаны), если вы не используете этот шаблон в.СЕТЬ. (спасибо @ohaal)
Другие вопросы по тегам