Regex фиксирует первое вхождение каждой группы в повторяющейся схеме - PullRequest
0 голосов
/ 22 ноября 2018

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

Name: John Doe\tAddress: Street 123 ABC\tCity: MyCity

У меня есть регулярное выражение (немного более сложное, но оно сводится к этому):

^(?:(?:(?:Name: (.+?))|(?:Address: (.+?))|(?:City: (.+?)))\t*)+$

, которое имеет три захватагруппы, которые могут захватывать значения имени, адреса и города (если они встречаются в тексте).Вот еще несколько примеров: https://regex101.com/r/37nemH/6. EDIT Порядок не фиксирован заранее, и также может случиться, что поля не разделены \t символами.

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

Name: John Doe\tAddress: Street 123 ABC\tCity: MyCity\tAddress: Other Address

Я бы хотел, чтобы вторая группа захвата совпадала с first address, то есть Street 123 ABC, и, предпочтительно, чтобы второе вхождение совпадало внутри группы "City", т.е.

1: John Doe
2: Street 123 ABC
3: MyCity\tAddress: Other Address

Концептуально, я попытался сделать это с отрицательным взглядом, например, заменив (?:Address: (.+?)) на (?:(?<!.*Address: )Address: (.+?)), то есть убедившись, что совпадение Address: не было где-то в тексте другим тегом Address:.Но отрицательный взгляд сзади не учитывает произвольную длину, поэтому это, очевидно, не сработает.

Можно ли это сделать с помощью регулярных выражений и как?

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Для заявленной проблемы вы можете использовать это регулярное выражение с условной конструкцией:

^.*?(?:(?:Name: (.+?)|(Address: )(.+?)|City: ((?(2).*?Address: )*.+?))\t*)+$

Демонстрация RegEx

Ваши значения доступны в захваченных группах 1,3, 4.

Группа захвата 2 предназначена для буквенной метки "Address: ".

Здесь (?(2).*?Address: )* - условная конструкция, которая означает, что если захваченная группа 2 присутствует, то в группе 4 текст совпадениядо следующего Address: будет найдено (0 или более совпадений).

Для текста Name: John Doe Address: Street 123 ABC City: MyCity Address: Second address он будет иметь следующие совпадения:

Group 1.    169-177 `John Doe`
Group 2.    178-187 `Address: `
Group 3.    187-201 `Street 123 ABC`
Group 4.    210-240 `MyCity Address: Second address`
0 голосов
/ 22 ноября 2018

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

Имя ( демо ):

^.*?Name:\s*(.*?)(?=\s*(?:Name:|Address:|City:|$))

Город ( демо ):

^.*?City:\s*(.*?)(?=\s*(?:Name:|Address:|City:|$))

Адрес ( демо ):

^.*?Address:\s*(.*?)(?=\s*(?:Name:|Address:|City:|$))

Подробности

  • ^ - начало строки
  • .*? - любые 0+ символов, кроме символов разрыва строки, как можно меньше
  • Address: - ключевое слово, на котором нужно остановиться и найтиожидаемое совпадение
  • \s* - 0+ пробелов
  • (.*?) - Группа 1: любые 0+ символов, кроме символов разрыва строки, как можно меньше ...
  • (?=\s*(?:Name:|Address:|City:|$)) - до, но исключая 0 или более пробелов, за которыми следуют Name:, Address:, City: или конец строки.
...