Строка регулярного выражения Python, выходящая для аргумента замены re.sub? - PullRequest
2 голосов
/ 09 октября 2019

Используя модуль re, можно использовать экранирование для шаблона замены. Например:

def my_replace(string, src, dst):
    import re
    return re.sub(re.escape(src), dst, string)

Хотя это работает по большей части, строка dst может включать, например, "\\9".

Это вызывает проблему:

  • \\1, \\2 ... и т. Д. В dst, литералы будут интерпретироваться как группы.
  • с использованием re.escape(dst) приводит к изменению . на \..

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


Пример использования:

>>> my_replace("My Foo", "Foo", "Bar")
'My Bar'

Пока все хорошо.


>>> my_replace("My Foo", "Foo", "Bar\\Baz")
...
re.error: bad escape \B at position 3

Это пытается интерпретировать \B как имеющее особое значение.


>>> my_replace("My Foo", "Foo", re.escape("Bar\\Baz"))
'My Bar\\Baz'

Работает!


>>> my_replace("My Foo", "Foo", re.escape("Bar\\Baz."))
'My Bar\\Baz\\.'

. экранируется, когда мы этого не хотим.


Хотя в этом случае можно использовать str.replace, вопрос о строке назначения остается полезным, поскольку могут быть моменты, когда мы хотим использовать другиефункции re.sub, такие как возможность игнорировать регистр.

Ответы [ 3 ]

1 голос
/ 09 октября 2019

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

def my_replace(string, src, dst):
    import re
    return re.sub(re.escape(src), dst.replace(r"\", r"\\"), string)
0 голосов
/ 09 октября 2019

Вы можете прибегнуть к разделению:

haystack = r"some text with stu\ff to replace"
needle = r"stu\ff"
replacement = r"foo.bar"

result = replacement.join(re.split(re.escape(needle), haystack))
print(result)

Это также должно работать с иглой в начале или в конце стога сена.

0 голосов
/ 09 октября 2019

Ваш код работает нормально, если вы просто удалите это re.escape, что я не уверен, почему у нас это будет:

Тест 1

import re 

def my_replace(src, dst, string):
    return re.sub(src, dst, string)


string = 'abbbbbb'
src = r'(ab)b+'
dst = r'\1z'

print(my_replace(src, dst, string))

Выход 1

abz

Тест 2

import re


def my_replace(src, dst, string):
    return re.sub(src, dst, string)


string = re.escape("abbbbbbBar\\Baz")
src = r'(ab)b+'
dst = r'\1z'

print(my_replace(src, dst, string))

Выход 2

abzBar\Baz

Тест 3

import re


def my_replace(src, dst, string):
    return re.sub(src, dst, string)


string = re.escape("abbbbbbBar\\Baz")
src = r'(ab)b+'
dst = r'\1' + re.escape('\\z')

print(my_replace(src, dst, string))

Выход 3

ab\zBar\\Baz

Тест 4

Чтобы построить dst, мы должны сначала знать, будем ли мы заменять нашу строку какими-либо группами захвата, такими как \1 в этом случае. Мы не можем re.escape \1, иначе мы заменили бы нашу строку на \\1, мы должны создать замену, если есть группы захвата, а затем добавить ее к любой другой части, которая требует повторного удаления.

import re


def my_replace(src, dst, string):
    return re.sub(src, dst, string)


string = re.escape("abbbbbbBar\\Baz")
src = r'(ab)b+'
dst = r'\1' + re.escape('\9z')

print(my_replace(src, dst, string))

Выход 4

ab\9zBar\\Baz
...