2016-11-24 5 views
1

Я пытаюсь понять метод group в библиотеке регулярных выражений Python. В этом контексте я пытаюсь выполнять подстановки в строке в зависимости от соответствующего объекта.Строковые подстановки на основе объекта-сопоставления (Python)

То есть, я хочу, чтобы заменить совпавшие объекты (+ и \n в данном примере) с определенной строкой в ​​my_dict словаре (с rep1 и rep2 соответственно).

Как видно из этого question и answer, Я попытался это:

content = ''' 
Blah - blah \n blah * blah + blah. 
''' 

regex = r'[+\-*/]' 

for mobj in re.finditer(regex, content): 
    t = mobj.lastgroup 
    v = mobj.group(t) 

    new_content = re.sub(regex, repl_func(mobj), content) 

def repl_func(mobj): 
    my_dict = { '+': 'rep1', '\n': 'rep2'} 
    try: 
     match = mobj.group(0) 
    except AttributeError: 
     match = '' 
    else: 
     return my_dict.get(match, '') 

print(new_content) 

Но я получаю None для t сопровождаемого IndexError при вычислении v.

Любые объяснения и примерный код будут оценены.

+0

Трудно угадать, что ваш код должен делать (есть много синтаксических ошибок, отступы нарушается логика неясна). Лучше вы приводите пример, описывающий то, что вы хотели бы достичь. – TomR8

+0

@ TomR8 Извинения! Я исправил все проблемы синтаксиса и опечатки (надеюсь). –

ответ

2

Regex r'[+\-*/]' не соответствует новой строке, поэтому ваш '\n': 'rep2' не будет использоваться. Идет добавление \n в регулярное выражение: r'[\n+*/-]'.

Далее, вы получите None, потому что ваше регулярное выражение не содержит named capturing groups см re docs:

match.lastgroup
Название последней подходящей захватывая группы, или None, если группа не имеют имя, или если ни одна группа не была сопоставлена ​​вообще.

Для замены используя матч, вам даже не нужно использовать re.finditer, используйте re.sub с лямбда в качестве замены:

import re 
content = ''' 
Blah - blah \n blah * blah + blah. 
''' 

regex = r'[\n+*/-]' 
my_dict = { '+': 'rep1', '\n': 'rep2'} 
new_content = re.sub(regex, lambda m: my_dict.get(m.group(),""), content) 
print(new_content) 
# => rep2Blah blah rep2 blah blah rep1 blah.rep2 

См Python demo

m.group() получает целое соответствует (весь матч хранится в match.group(0)). Если у вас пару неэкранированных скобок в шаблоне, он будет создавать capturing group, и вы можете получить доступ к первому один с m.group(1) и т.д.

2

Несмотря на поистине вещий ответ Wiktor, есть все еще вопрос, почему оригинал алгоритм Wouldn Ор в Не работай. В основном есть 2 проблемы:

Вызов new_content = re.sub(regex, repl_func(mobj), content) заменит все матчи из regex с восстановительной стоимостью самого первого матча.

Правильный звонок должен быть new_content = re.sub(regex, repl_func, content). Как задокументировано here, repl_func динамически вызывается с текущим объектом совпадения!

repl_func(mobj) делает некоторые ненужную обработку исключений, которые могут быть упрощены:

my_dict = {'\n': '', '+':'rep1', '*':'rep2', '/':'rep3', '-':'rep4'} 
def repl_func(mobj): 
    global my_dict 
    return my_dict.get(mobj.group(0), '') 

Это эквивалентно решению Wiktor - он просто избавились от самого определения функции с помощью лямбда-выражения.

С этой модификацией цикл for mobj in re.finditer(regex, content): стал превосходным, поскольку он выполняет одни и те же вычисления несколько раз.

Только для полноты здесь находится рабочее решение с использованием re.finditer(). Он строит строки результата от соответствующих срезов из content:

my_regx = r'[\n+*/-]' 
my_dict = {'\n': '', '+':'rep1'  , '*':'rep2', '/':'rep3', '-':'rep4'} 
content = "A*B+C-D/E" 
res = "" 
cbeg = 0 
for mobj in re.finditer(my_regx, content): 
    # get matched string and its slice indexes 
    mstr = mobj.group(0) 
    mbeg = mobj.start() 
    mend = mobj.end() 

    # replace matched string 
    mrep = my_dict.get(mstr, '') 

    # append non-matched part of content plus replacement 
    res += content[cbeg:mbeg] + mrep 

    # set new start index of remaining slice 
    cbeg = mend 

# finally add remaining non-matched slice 
res += content[cbeg:] 
print (res) 
Смежные вопросы