Как заменить только часть совпадения на python re.sub

Мне нужно сопоставить два случая одним reg-выражением и выполнить замену

'long.file.name.jpg' -> 'long.file.name_suff.jpg'

'long.file.name_a.jpg' -> 'long.file.name_suff.jpg'

Я пытаюсь сделать следующее

re.sub('(\_a)?\.[^\.]*$' , '_suff.',"long.file.name.jpg")

Но это сокращение расширения «.jpg», и я получаю

длинное.имя.файла_suff. вместо long.file.name_suff.jpg Я понимаю, что это из-за части [^.]*$, но я не могу ее исключить, потому что мне нужно найти последнее вхождение '_a' для замены или последнего '.'

Есть ли способ заменить только часть матча?


person Arty    schedule 04.05.2010    source источник
comment
почему вы избегаете подчеркивания (\\_a)?   -  person Amarghosh    schedule 04.05.2010


Ответы (4)


 re.sub(r'(?:_a)?\.([^.]*)$', r'_suff.\1', "long.file.name.jpg")

?: запускает несоответствующую группу (ответ SO), поэтому (?:_a) соответствует _a, но не перечисляет его, следующий вопросительный знак делает его необязательным.

Таким образом, на английском языке это означает, что нужно соответствовать окончанию .<anything>, которое следует (или не следует) шаблону _a.

Другой способ сделать это — использовать lookbehind (см. здесь). Упоминаю об этом, потому что они суперполезны, но я не знал о них за 15 лет выполнения RE.

person Amarghosh    schedule 04.05.2010

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

re.sub(r'(\_a)?\.([^\.]*)$' , r'_suff.\2',"long.file.name.jpg")
person Amber    schedule 04.05.2010
comment
@Amber: из вашего ответа я сделал вывод, что, в отличие от str.replace(), мы не можем использовать переменные а) в необработанных строках; или б) в качестве аргумента re.sub; или в) оба. а) имеет смысл (я думаю), но я не уверен насчет б). Кажется, мы можем использовать имя переменной для строки, через которую проходит регулярное выражение. Не могли бы вы разъяснить? Спасибо. - person Malik A. Rumi; 09.06.2017
comment
какие части захватывают и ссылаются на него? - person cryanbhu; 17.11.2020

Просто поместите выражение для расширения в группу, зафиксируйте его и укажите соответствие в замене:

re.sub(r'(?:_a)?(\.[^\.]*)$' , r'_suff\1',"long.file.name.jpg")

Кроме того, использование незахватывающей группы (?:…) предотвратит повторное сохранение большого количества ненужной информации.

person Gumbo    schedule 04.05.2010

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

re.sub(r'(?<=long.file.name)(\_a)?(?=\.([^\.]*)$)' , r'_suff',"long.file.name.jpg")
>>> 'long.file.name_suff.jpg'

Части long.file.name и .jpg используются при сопоставлении, но не подлежат замене.

person Ahmet DAL    schedule 11.06.2015