регулярные выражения javascript - группы - PullRequest
4 голосов
/ 03 июня 2019

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

/(\S+) (\S*) ?\b(\S+)/

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

Что мне трудно понять, так это функция граничного условия для начала совпадения последней группы в начале третьего слова.

Когда есть три слова, не имеет значения, включено это или нет.

enter image description here enter image description here

Когда есть только два слова, существует разница между группой № 2 и группой № 3

enter image description here enter image description here

Итак, мой вопрос таков

Когда есть два слова, почему присутствие \b приводит к тому, что group # 2 будет пустой строкой, как и ожидалось, но когда ее нет, group # 2 содержать второе слово минус последнюю букву и group # 3 для хранения последней буквы второго слова?

Ответы [ 2 ]

2 голосов
/ 03 июня 2019

Когда есть два слова, почему присутствие \ b приводит к тому, что группа # 2 становится пустой строкой, как и ожидалось

Посмотрите на первую и третью группы - будучи (\S+), они должны содержать символы. Когда есть два слова, эти два слова должны входить в первую и третью группы - во вторую группу, поскольку она повторяется с *, не будет потреблять никаких символов и будет пустой строкой.

но когда отсутствует, группа № 2 содержит второе слово минус последняя буква, а группа № 3 содержит последнюю букву второго слова?

Когда шаблон

(\S+) (\S*) ?(\S+)

как только двигатель соответствует первому слову, двигатель начнет пытаться сопоставить второе слово. Таким образом, если ввод foo bar, мы можем рассмотреть, как шаблон (\S*) ?(\S+) работает на bar.

Движок сначала пытается использовать все оставшиеся символы в строке с \S*. Это терпит неудачу, потому что последняя группа должна содержать хотя бы один символ, поэтому движок выполняет резервное копирование шага, и группа \S* соответствует всем, кроме последнего символа. Это приводит к успешному совпадению, потому что позиция перед последним символом соответствует \s?(\S+).

Вы можете увидеть этот процесс визуально здесь:

https://regex101.com/r/RAkEOt/1/debugger

enter image description here

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

enter image description here

Исходный шаблон может быть слегка ошибочным - \b соответствует границе слова , но не каждый непробельный символ является символом слова - он (вероятно, нежелательно) соответствует foo it's, где it' переходит во вторую группу, а s переходит в третью группу.

1 голос
/ 03 июня 2019

Разница исходит от второй группы (\S*) - она ​​будет захватывать любое количество непробельных символов. Таким образом, если у вас есть два слова, но три группы, последняя из которых (\S+) - соответствует хотя бы одному непробельному символу, механизм регулярных выражений попытается удовлетворить обе группы 2 и 3.

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

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

let [ , group1, group2, group3] = "the brown".match(/(\S+) (\S*) ?(\S{2,})/);

console.log("group 1:", group1)
console.log("group 2:", group2)
console.log("group 3:", group3)

Когда вы вместо этого добавляете границу слова \b к шаблону, у группы 2 не должно быть символов и , удовлетворяющих более позднему условию - когда регулярное выражение потребляет символ, остальная часть шаблона будет только продолжайте с этого символа и далее, следовательно, вы не можете иметь, например, группу 2, соответствующую b, а затем иметь границу слова, за которой следует rown. Единственный способ удовлетворения (\S+) (\S*) ?\b(\S+) заключается в следующем:

  • группа 1 матчей the
  • пробел соответствует символу
  • группа 2 не соответствует ничему, что является приемлемым, поскольку может соответствовать любому количеству, включая ноль
  • необязательный пробел соответствует нулю пробелов
  • есть граница слова
  • группа 3 потребляет остальные буквы - brown
...