2014-12-23 3 views
2

Я хочу заменить текст совпадающих шаблонов re в строке и сделать это с помощью re.sub(), если передать его в качестве аргумента repl в вызове, он работает по желанию, как показано ниже :Замена названных групп захвата на re.sub

from __future__ import print_function 
import re 

pattern = r'(?P<text>.*?)(?:<(?P<tag>\w+)>(?P<content>.*)</(?P=tag)>|$)' 

my_str = "Here's some <first>sample stuff</first> in the " \ 
      "<second>middle</second> of some other text." 

def replace(m): 
    return ''.join(map(lambda v: v if v else '', 
         map(m.group, ('text', 'content')))) 

cleaned = re.sub(pattern, replace, my_str) 
print('cleaned: {!r}'.format(cleaned)) 

Выход:

cleaned: "Here's some sample stuff in the middle of some other text." 

Однако из документации это звучит, как я должен быть в состоянии получить те же результаты, просто передавая ему строку замены со ссылками на названных групп в нем. Однако моя попытка сделать это не сработала, потому что иногда группа не имеет себе равных, а возвращаемое значение равно None (а не пустая строка '').

cleaned = re.sub(pattern, r'\g<text>\g<content>', my_str) 
print('cleaned: {!r}'.format(cleaned)) 

Выход:

Traceback (most recent call last): 
    File "test_resub.py", line 21, in <module> 
    cleaned = re.sub(pattern, r'\g<text>\g<content>', my_str) 
    File "C:\Python\lib\re.py", line 151, in sub 
    return _compile(pattern, flags).sub(repl, string, count) 
    File "C:\Python\lib\re.py", line 278, in filter 
    return sre_parse.expand_template(template, match) 
    File "C:\Python\lib\sre_parse.py", line 802, in expand_template 
    raise error, "unmatched group" 
sre_constants.error: unmatched group 

Что я делаю неправильно или не понимая?

+0

«Содержание» последнего совпадения - None ... – kennytm

+0

@KennyTM: Я знаю, что некоторые из групп соответствия будут 'None', поэтому я использую' lambda v: v if v else '' ' в функции 'replace()'. Что-то в этом нуждается в заменяющей строке, и если да, то как это делается? – martineau

ответ

2
def repl(matchobj): 
    if matchobj.group(3): 
     return matchobj.group(1)+matchobj.group(3) 
    else: 
     return matchobj.group(1) 

my_str = "Here's some <first>sample stuff</first> in the " \ 
     "<second>middle</second> of some other text." 

pattern = r'(?P<text>.*?)(?:<(?P<tag>\w+)>(?P<content>.*)</(?P=tag)>|$)' 
print re.sub(pattern, repl, my_str) 

Вы можете использовать функцию вызова re.sub.

Edit: cleaned = re.sub(pattern, r'\g<text>\g<content>', my_str) это не будет работать, как, когда последний бит строки соответствует т.е. of some other text. есть \g<text> определено, но не \g<content> как есть не content.But вы еще спрашиваете re.sub сделать it.So он генерирует ошибку. Если вы используете строку "Here's some <first>sample stuff</first> in the <second>middle</second>", то ваш print re.sub(pattern,r"\g<text>\g<content>", my_str) будет работать как \g<content> определяется здесь все время.

+0

Я знаю, что вы можете передать функцию 're.sub()' - вот что делает первый бит-код в моем вопросе. Я хотел бы знать, как это сделать, передав заменяющую строку, содержащую ссылки на именованные (или пронумерованные) группы. – martineau

+0

Итак, вы говорите, что невозможно обработать, когда группа в шаблоне не была сопоставлена ​​- даже если шаблон в целом был сопоставлен, так как он допускает ноль или более случаев в группе), за исключением того, .sub() 'функция? Я надеялся, что это неверно, и есть определенная условная форма ссылки на названную группу захвата. – martineau

+0

@martineau, поэтому мы можем использовать функцию там для такого типа ситуаций. – vks

1

Если я правильно понимаю, вы хотите, чтобы удалить все между < > включено:

>>> import re 

>>> my_str = "Here's some <first>sample stuff</first> in the <second>middle</second> of some other text." 

>>> print re.sub(r'<.*?>', '', my_str) 

Here's some sample stuff in the middle of some other text. 

В некоторой степени объяснить, что происходит тут ... r'<.*?>':

< находит первый <

. затем принять любые символы

* принимает любой символу, любое количество раз

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

> найти точку закрытия >

Затем замените все между этими двумя точками ничем.

+0

Я хочу удалить, как в замене ничем, все '' s и соответствующие '', но сохранить все остальное, включая все, что между ними. – martineau

+1

Мое предложение должно делать именно это ...Если у вас что-то отсутствует, вы можете указать полную строку, с которой работаете, чтобы мы могли помочь. – Jkdc

+0

Вся строка в моем вопросе, она находится в переменной 'my_str'. Я назвал группы захвата в своем регулярном выражении и хотел бы ссылаться на них в заменяющей строке, переданной в 're.sub()'. Ваше вспомогательное предложение не делает этого, поэтому оно не кажется полезным, потому что оно не отвечает на вопрос, который я задал, и как ссылаться на них в заменяющей строке без ошибок. – martineau

Смежные вопросы