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

Из этого 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#

Ответ 1

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

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

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

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

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

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

Ответ 2

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

Бывает простой, общий вариант, который не упоминался.

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

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

Идея состоит в том, что мы сопоставляем, но игнорируем что-либо в кавычках, чтобы нейтрализовать этот контент (в левой части чередования). С правой стороны мы фиксируем все +, которые не были нейтрализованы в группу 1, а функция replace рассматривает группу 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);

Онлайн-демонстрация

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

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

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

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

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

См. демо.

Что можно сказать о побежденных цитатах?

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

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

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

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

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

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

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

Смотрите демо-версию regex и полный script.

Ссылка

Ответ 3

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

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

Код ниже

// 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"}'

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

Ответ 4

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

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

и

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

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

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