Как захватить и заменить все шаблоны в строке, содержащей отдельный шаблон, с помощью регулярных выражений - PullRequest
2 голосов
/ 04 апреля 2019

Я пытаюсь настроить регулярное выражение, которое позволит мне заменить 2 пробела на табуляцию, но только в строках, содержащих определенный шаблон.

foo: here  is  some  sample  text
bar: here  is  some  sample  text

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

foo: here  is  some  sample  text
bar: here    is    some    sample    text

Самое близкое, что я получил, использовало это:

Find: ^(\s.*)(bar)(.*)  (.*)
Replace: \1\2\3\t\4

Однако это заменяет только одну группу из двух пробелов за раз, поэтому я в итоге получаю следующее:

foo: here  is  some  sample  text
bar: here  is  some  sample    text

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

Я использую Sublime Text, но я почти уверен, что он использует PCRE для своего регулярного выражения.

Ответы [ 2 ]

2 голосов
/ 04 апреля 2019

Это также работает

(?m-s)(?:^(?=.*\bbar\b)|(?!^)\G).*?\K[ ]{2}

https://regex101.com/r/vnM649/1
или
https://regex101.com/r/vnM649/2

Объяснено

 (?m-s)               # Multi-line mode, not Dot-All mode
 (?:
      ^                    # Only test at BOL for 'bar'
      (?= .* \b bar \b )
   |                     # or,
      (?! ^ )              # Not BOL, must have found 2 spaces in this line before
      \G                   # Start where last 2 spaces left off
 )
 .*?                  # Minimal any character (except newline)
 \K                   # Ignore anything that matched up to this point
 [ ]{2}               # 2 spaces to replace with a \t

possible to translate this to work with Python?

Да.

Конструкция \G дает возможность сделать все это за один проход регулярного выражения.Модуль Python regex поддерживает его, но не модуль re.Если вы используете модуль re, вам нужно сделать это в 2 шага.

Сначала нужно сопоставить строку (и), где bar равно
, а затем передать его обратному вызову, чтобы заменить все double
пробелы во вкладках, затем верните его как замену
обратно вызывающей стороне.

Пример кода Python:

https://rextester.com/AYM96859

 #python 2.7.12

 import re

 def replcall(m):
     contents = m.group(1)
     return re.sub( r'[ ]{2}',"\t", contents )

 str = (
 r'foo: here  is  some  sample  text' + "\n"
 r'bar: here    is    some    sample    text' + "\n"
 )

 newstr = re.sub( r'(?m)(^(?=.*\bbar\b)(?=.*[ ]{2}).*)', replcall, str )

 print newstr

Регулярное выражение для получения строки, расширенное:

 (?m)
 (                             # (1 start)
      ^ 
      (?= .* \b bar \b )
      (?= .* [ ]{2} )
      .* 
 )                             # (1 end)
0 голосов
/ 04 апреля 2019

Это будет работать:

Find: (^(?!.*bar).*)|  
Replace: \1\t

(обратите внимание на 2 пробела в конце регулярного выражения "find"), но в конце строки foo будет добавлена ​​вкладка.

См. здесь демонстрация PCRE.

...