регулярное выражение для соответствия, но заменяет только часть шаблона в python
Все примеры переполнения стека, которые я нашел , слишком сложны для реинжиниринга .
Рассмотрим этот игрушечный пример
s = "asdfasd a_b dsfd"
я хочу s = "asdfasd a'b dsfd"
То есть: найдите два символа, разделенных подчеркиванием, и замените это подчеркивание апострофом
Попытка:
re.sub("[a-z](_)[a-z]","'",s)
# "asdfasd ' dsfd"
Я думал, ()
они должны решить эту проблему?
Еще больше сбивает с толку тот факт, что, похоже, мы успешно нашли персонажа, которого хотим заменить:
re.findall("[a-z](_)[a-z]",s)
#['_']
почему это не заменяют?
благодаря
Ответы
Используйте шаблоны просмотра вперед и назад:
re.sub("(?<=[a-z])_(?=[a-z])","'",s)
Шаблоны «смотреть вперед / назад» имеют нулевую ширину и поэтому ничего не заменяют.
UPD:
- Проблема заключалась в том, что
re.sub
будет заменено все совпадающее выражение, включая предыдущую и следующую буквы. re.findall
все еще соответствовало всему выражению, но у него также была группа (скобка внутри), которую вы заметили. Весь матч был по-прежнемуa_b
- Выражения lookahead / lookbehind проверяют, что поиску предшествует / следует шаблон, но не включают его в соответствие.
- Другой вариант заключался в создании нескольких групп и замене этих групп:
re.sub("([a-z])_([a-z])", r"\1'\2", s)
При использовании re.sub
сохраняемый текст должен быть захвачен, а удаляемый текст - нет.
Использовать
re.sub(r"([a-z])_(?=[a-z])",r"\1'",s)
Смотрите доказательство .
ОБЪЯСНЕНИЕ
NODE EXPLANATION
--------------------------------------------------------------------------------
( group and capture to \1:
--------------------------------------------------------------------------------
[a-z] any character of: 'a' to 'z'
--------------------------------------------------------------------------------
) end of \1
--------------------------------------------------------------------------------
_ '_'
--------------------------------------------------------------------------------
(?= look ahead to see if there is:
--------------------------------------------------------------------------------
[a-z] any character of: 'a' to 'z'
--------------------------------------------------------------------------------
) end of look-ahead
Код Python :
import re
s = "asdfasd a_b dsfd"
print(re.sub(r"([a-z])_(?=[a-z])",r"\1'",s))
Вывод:
asdfasd a'b dsfd
re.sub
Заменит все это совпало.
Существует более общий способ решения вашей проблемы, и вам не нужно повторно изменять регулярное выражение.
Код ниже:
import re
s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"
r = "am_replace_str"
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, r,match.group(0)) if _reg else r
#
re.sub(reg,repl, s)
вывод: 'Data: year=am_replace_str, monthday=am_replace_str, month=am_replace_str, some other text'
Конечно, если в вашем кейсе нет групп, вашему коду может понравиться это:
import re
s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"
r = "am_replace_str"
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, r,match.group(0))
#
re.sub(reg,repl, s)