Регулярное выражение для соответствия всех экземпляров не в кавычках - PullRequest
53 голосов
/ 24 июня 2011

Из этого q / a я пришел к выводу, что сопоставить все экземпляры данного регулярного выражения , а не внутри кавычек, невозможно.То есть он не может соответствовать экранированным кавычкам (например: "this whole \"match\" should be taken").Если есть способ сделать это, о котором я не знаю, это решило бы мою проблему.

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

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

Например: Строка ввода:+bar+baz"not+or\"+or+\"this+"foo+bar+замена + на #, а не внутри кавычек, вернет:#bar#baz"not+or\"+or+\"this+"foo#bar#

Ответы [ 4 ]

90 голосов
/ 24 июня 2011

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

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

\+(?=([^"]*"[^"]*")*[^"]*$)

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

\+(?=([^"\\]*(\\.|"([^"\\]*\\.)*[^"\\]*"))*[^"]*$)

Я признаю, что это маленький загадочный.=)

49 голосов
/ 15 мая 2014

Азмисов, воскрешает этот вопрос, потому что вы сказали, что искали any efficient alternative that could be used in JavaScript и any elegant solutions that would work in most, if not all, cases.

Это простое общее решение, которое не было упомянуто.

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

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

Идея состоит в том, что мы сопоставляем, но игнорируем что-либо в кавычках, чтобы нейтрализовать это содержимое (в левой части чередования). С правой стороны мы фиксируем все +, которые не были нейтрализованы в Группе 1, и функция замены исследует Группу 1. Вот полный рабочий код:

<script>
var subject = '+bar+baz"not+these+"foo+bar+';
var regex = /"[^"]+"|(\+)/g;
replaced = subject.replace(regex, function(m, group1) {
    if (!group1) return m;
    else return "#";
});
document.write(replaced);

Демо онлайн

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

Надеюсь, это даст вам другое представление об очень общем способе сделать это. :)

А как насчет пустых строк?

Выше приведен общий ответ для демонстрации техники. Его можно настроить в зависимости от ваших потребностей. Если вы беспокоитесь, что ваш текст может содержать пустые строки, просто измените квантификатор внутри выражения захвата строк с + на *:

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

См. демо .

А как насчет кавычек?

Опять же, приведенный выше является общим ответом для демонстрации техники. Регулярное выражение " ignore this match " может быть уточнено не только для ваших нужд, но и для добавления нескольких выражений, которые можно игнорировать. Например, если вы хотите убедиться, что экранированные кавычки должным образом игнорируются, вы можете начать с добавления чередования \\"| перед двумя другими, чтобы сопоставить (и игнорировать) запятые экранированные двойные кавычки.

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

Полученное выражение имеет три ветви:

  1. \\" для соответствия и игнорировать
  2. "(?:\\"|[^"])*" для сопоставления и игнорирование
  3. (\+) для сопоставления, захват и обработка

Обратите внимание, что в других разновидностях регулярных выражений мы могли бы легче выполнять эту работу с lookbehind, но JS не поддерживает ее.

Полное регулярное выражение становится:

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

См. regex demo и полный скрипт .

Ссылка

  1. Как сопоставить шаблон с исключением ситуаций s1, s2, s3
  2. Как сопоставить шаблон, если ...
6 голосов
/ 24 июня 2011

Вы можете сделать это в три этапа.

  1. Используйте regex global replace для извлечения всего содержимого тела строки в боковую таблицу.
  2. Сделайте перевод запятой
  3. Используйте регулярное выражение regex для замены тела строк обратно

код ниже

// Step 1
var sideTable = [];
myString = myString.replace(
    /"(?:[^"\\]|\\.)*"/g,
    function (_) {
      var index = sideTable.length;
      sideTable[index] = _;
      return '"' + index + '"';
    });
// Step 2, replace commas with newlines
myString = myString.replace(/,/g, "\n");
// Step 3, swap the string bodies back
myString = myString.replace(/"(\d+)"/g,
    function (_, index) {
      return sideTable[index];
    });

Если вы запустите это после установки

myString = '{:a "ab,cd, efg", :b "ab,def, egf,", :c "Conjecture"}';

вы должны получить

{:a "ab,cd, efg"
 :b "ab,def, egf,"
 :c "Conjecture"}

Работает, потому что после шага 1

myString = '{:a "0", :b "1", :c "2"}'
sideTable = ["ab,cd, efg", "ab,def, egf,", "Conjecture"];

поэтому единственные запятые в myString - это внешние строки. Шаг 2, затем превращает запятые в новые строки:

myString = '{:a "0"\n :b "1"\n :c "2"}'

Наконец, мы заменяем строки, содержащие только цифры, на их исходное содержимое.

1 голос
/ 25 октября 2015

Хотя ответ zx81 кажется наиболее эффективным и чистым, он нуждается в следующих исправлениях, чтобы правильно перехватить экранированные кавычки:

var subject = '+bar+baz"not+or\\"+or+\\"this+"foo+bar+';

и

var regex = /"(?:[^"\\]|\\.)*"|(\+)/g;

Также уже упоминалось "group1 === undefined" или "! Group1". Особенно 2. Кажется важным принять во внимание все, что было задано в первоначальном вопросе.

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

...