Использование групп захвата в пределах поиска - PullRequest
3 голосов
/ 10 марта 2020

Предположим, нам дана следующая строка:

a, b, c, d
e, f, g, h
i, j, k, l

I wi sh для преобразования этой строки в следующую строку с использованием регулярного выражения PCRE:

ab, ac, ad
ef, eg, eh
ij, ik, il

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

Если это невозможно, может следующая строка быть произведенным?

a, ab, ac, ad
e, ef, eg, eh
i, ij, ik, il

Пожалуйста, продемонстрируйте свое регулярное выражение, используя функцию "ЗАМЕНА" (которая может включать обратные ссылки, такие как $1) на regex101.com. Я был бы особенно признателен за объяснение того, как механизм PCRE проходит через строку.

Если это невозможно сделать с помощью регулярного выражения PCRE, мне хотелось бы объяснить, почему это невозможно.

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

Ответы [ 2 ]

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

Это может быть сделано только с помощью механизма регулярных выражений, который поддерживает шаблоны обратной ширины переменной ширины, а PCRE - нет. Пересматриваемая переменная ширина необходима для ссылки на слово в начале каждой строки для каждого последующего слова.

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

(?<=(\w+),.*)(\w+)|^\w+,\s*

и замените спички на:

$1$2

Демо: https://regex101.com/r/XZhZyW/5/

0 голосов
/ 23 марта 2020

Я хотел бы упомянуть возможный ход действий при столкновении с ситуацией, например, здесь, где требуется положительный просмотр переменной длины, но используемый механизм регулярных выражений не поддерживает эту операцию, но поддерживает положительные взгляды переменной длины. Как и PCRE (PHP), например.

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

Basi c idea

  • Перевернуть строку
  • Использовать регулярное выражение с соответствующим положительным прогнозом для замены совпадений
  • Перевернуть результирующую строку

Пример

Предположим, мы wi sh преобразуем следующие строки:

a, bb, c, d
ee, f, g, h
i, j, kk, l

в строки:

abb, ac, ad
eef, eeg, eeh
ij, ikk, il

Сначала мы переворачиваем исходные строки:

d ,c ,bb ,a
h ,g ,f ,ee
l ,kk ,j ,i

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

(\w+)(?=.*,(\w+)$)|\s+,\w+$ 

и заменяем каждое совпадение на $1+$2, чтобы получить:

da ,ca ,bba
hee ,gee ,fee
li ,kki ,ji

Наконец, переверните эти строки:

abb, ac, ad
eef, eeg, eeh    
ij, ikk, il

PCRE demo

Регулярное выражение выполняет следующие операции:

(\w+)    # match 1+ word chars in cap grp 1 
(?=      # begin a positive lookahead
  .*,    # match 0+ chars (greedily), then ','
  (\w+)  # match 1+ word chars in cap grp 1
  $
)
|
\s+,\w+
$ 

Я буду представлять пробелы в строке "a, bb, c, d" с небольшими смайликами (), чтобы сделать их более четкими и отобразить строку таким образом:

 a , ☺ b b , ☺ c , ☺ d
^

Пробелы теперь представляют области между соседними символами. ^ - начальное расположение указателя движка регулярных выражений.

После того, как (\w+) соответствует "a" в начале строки (обозначено m ниже), "a" сохраняется в группу захвата. 1. Позитивный прогноз начинается сразу после этого матча:

 a , ☺ b b , ☺ c , ☺ d
 m^

Позитивный прогноз (?=.*,(\w+)$) сохраняет "d", чтобы захватить группу 2. 1 Поскольку матч был успешным, При первом совпадении "a" заменяется на $1+$2 #=> "ad", и указатель перемещается обратно на свою позицию до того, как был выполнен поиск:

 a , ☺ b b , ☺ c , ☺ d
  ^

Теперь есть попытка сопоставить (\w+) с частью строка, которая начинается с первой запятой. Это терпит неудачу, как и или часть регулярного выражения, \s+,\w+$. Затем указатель передвигается на один символ:

 a , ☺ b b , ☺ c , ☺ d
    ^

Это также не удается, и указатель снова передвигается на единицу.

 a , ☺ b b , ☺ c , ☺ d
      ^

(\w+) теперь соответствует "bb", что сохраняется для захвата группы 1, и в этот момент:

 a , ☺ b b , ☺ c , ☺ d
       m m^

Как и прежде, положительный прогноз сохраняет "d" для захвата группы 2 и совпадения, "bb" заменяется на $1+$2 #=> "bbd"

После еще двух совпадающих сбоев мы находимся по адресу:

 a , ☺ b b , ☺ c , ☺ d
              ^

По тем же причинам, что и раньше, "c" сопоставляется и заменяется на $1+$2 => "cd", и мы сейчас здесь:

 a , ☺ b b , ☺ c , ☺ d
                ^

Больше нет строк слов, за которыми следуют строки слов, которые должны быть сопоставлены, но конец строки, ", d", теперь соответствует части или регулярного выражения \s+,\w+$. Это совпадение затем заменяется на $1+$2. Однако на этот раз две группы захвата пусты, поэтому совпадение заменяется пустой строкой.

1 Необходима запятая. Без этого .*, будучи жадным, сожрал бы все до последнего символа слова. Например, если строка заканчивается ", cd", группа захвата 2 будет содержать только "d".

...