javascript регулярное выражение заменить последний шаблон в строке? - PullRequest
0 голосов
/ 10 марта 2020

У меня есть строка, которая выглядит как

var std = new Bammer({mode:"deg"}).bam(0, 112).bam(177.58, (line-4)/2).bam(0, -42)
  .ramBam(8.1, 0).bam(8.1, (slot_height-thick)/2)

Я хочу поместить тег вокруг последнего .bam() или .ramBam().

str.replace(/(\.(ram)?bam\(.*?\))$/i, '<span class="focus">$1</span>');

И я надеюсь получить :

new Bammer({mode:"deg"}).bam(0, 112).bam(177.58, (line-4)/2).bam(0, -42).ramBam(8.1, 0)<span class="focus">.bam(8.1, (slot_height-thick)/2)</span>

Но почему-то я продолжаю бороться с не жадным параметром, он оборачивает все после нового Bammer тегами span. Также пробовал вопросительный знак после $, чтобы сделать группу не жадной.

Я надеялся сделать это легко, а с bam или ramBam я думал, что регулярное выражение будет самым простым решением но я думаю, что я не прав.

Где я go не прав?

Ответы [ 3 ]

3 голосов
/ 11 марта 2020

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

(?!.*\)\.)(\.(?:bam|ramBam)\(.*\))$

Демо

(?!.*\)\.)         # do not match ').' later in the string
(                  # begin capture group 1                   
  .\               # match '.'
  (?:bam|ramBam)   # match 'bam' or 'ramBam' in non-cap group
  \(.*\)           # match '(', 0+ chars, ')'
)                  # end capture group 1
$                  # match end of line

Для примера, приведенного в вопросе, отрицательный взгляд вперед (?!.*\)\.) перемещает внутренний указатель на непосредственно перед подстрокой:

.bam(8.1, (slot_height-thick)/2)

, так как это первое местоположение, в котором нет подстроки ). позже в строке.

Если не было конца якорь строки $ и строка заканчивается:

...0).bam(8.1, (slot_height-thick)/2)abc

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

...0)<span class="focus">.bam(8.1, (slot_height-thick)/2)</span>abc

Включая конец строки anchor предотвращает подстановку, если строка не заканчивается содержимым предполагаемой группы захвата.

2 голосов
/ 11 марта 2020

Используемое регулярное выражение:

/\.((?:ram)?[bB]am\([^)]*\))(?!.*\.(ram)?[bB]am\()/
  1. \. Период совпадений.
  2. (?:ram)? По выбору соответствует ram в без захвата группа.
  3. [bB]am Совпадения bam или Bam.
  4. \( Совпадения (.
  5. [^)]* Совпадения, содержащие не менее 0 символов поскольку они не ).
  6. ) Соответствует ). Элементы с 2 по 6. помещаются в группу захвата 1.
  7. (?!.*\.(ram)?[bB]am\() Это отрицательное утверждение о том, что остальная часть строки не содержит дальнейшего экземпляра .ram( или .rambam( или * 1034. * и, следовательно, это последний экземпляр.

См. демонстрацию Regex

let str = 'var std = new Bammer({mode:"deg"}).bam(0, 112).bam(177.58, 0).bam(0, -42).ramBam(8.1, 0).bam(8.1, slot_height)';
console.log(str.replace(/\.((?:ram)?[bB]am\([^)]*\))(?!.*\.(ram)?[bB]am\()/, '<span class="focus">.$1</span>'));

Обновление

Механизм регулярных выражений JavaScript недостаточно мощен для обработки вложенных скобок. Единственный способ решения этой проблемы, который я знаю, - это если предположить, что после последнего вызова bam или ramBam в строке больше нет посторонних правых скобок. Тогда, когда я сканировал выражение в скобках с помощью \([^)]*\), которое не смогло бы взять окончательные скобки, мы теперь должны использовать \(.*\), чтобы сканировать все до последних скобок. По крайней мере, я не знаю другого пути. Но это также означает, что способ, который я использовал для определения конечного экземпляра ram или ramBam с использованием отрицательного прогноза, требует небольшой корректировки. Мне нужно убедиться, что у меня есть окончательный экземпляр ram или ramBam до . Я начинаю делать любые жадные совпадения:

(\.(?:bam|ramBam)(?!.*\.(bam|ramBam)\()\((.*)\))

См. Regex Demo

  1. \. Соответствует ..
  2. (?:bam|ramBam) Соответствует bam или ramBam.
  3. (?!.*\.(bam|ramBam)\() Утверждает, что пункт 1. был последним экземпляром
  4. \( Матчи (.
  5. (.*) Жадно сопоставляет все до ...
  6. \) финал ).
  7. ) Элементы с 1 по 6. помещаются в группу захвата 1.

let str = 'var std = new Bammer({mode:"deg"}).bam(0, 112).bam(177.58, (line-4)/2).bam(0, -42) .ramBam(8.1, 0).bam(8.1, (slot_height-thick)/2)';
console.log(str.replace(/(\.(?:bam|ramBam)(?!.*\.(bam|ramBam)\()\((.*)\))/, '<span class="focus">$1</span>'));
1 голос
/ 10 марта 2020

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

str.replace(/(\.(?:ram)?[Bb]am\([^)]*\)(?!.*(ram)?[Bb]am))/i, '<span class="focus">$1</span>');

Обратите внимание, что это заменит только последнее имя функции (bam ИЛИ ramBam), но не оба. Вам нужно будет использовать несколько иной подход, чтобы заменить их обоих.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...