基于匹配对象的字符串替换(Python)

时间:2016-11-24 14:55:56

标签: python regex python-3.x

我很难理解Python正则表达式库中的group方法。在这种情况下,我尝试根据匹配对象对字符串进行替换。

也就是说,我想用+字典中的特定字符串替换匹配的对象(本例中为\nmy_dict)(rep1和{分别为{1}}。

从此questionanswer可以看出, 我试过这个:

rep2

但在计算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

任何解释和示例代码都将不胜感激。

2 个答案:

答案 0 :(得分:2)

r'[+\-*/]'正则表达式与换行符不匹配,因此不会使用'\n': 'rep2'。否则,请将\n添加到正则表达式:r'[\n+*/-]'

接下来,您获得None,因为您的正则表达式不包含任何named capturing groups,请参阅re docs

  

<强> match.lastgroup
  最后匹配的捕获组的名称,如果该组没有名称,或者根本没有匹配任何组,则为 None

要使用匹配进行替换,您甚至不需要使用re.finditer,请使用re.sub并将lambda作为替换:

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)等访问第一个括号。

答案 1 :(得分:2)

尽管Wiktor真正的pythonic答案,仍然存在为什么OP的原始算法不起作用的问题。 基本上有两个问题:

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的解决方案 - 他只是通过使用lambda表达式来摆脱函数定义本身。

通过这种修改,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)