Python正则表达式立即用组名替换组

时间:2016-04-29 17:44:51

标签: python regex replace

以下重新:

import re
s = "the blue dog and blue cat wore 7 blue hats 9 days ago"
p = re.compile(r'blue (?P<animal>dog|cat)')
p.sub(r'\1',s)

结果,

'the dog and cat wore 7 blue hats 9 days ago'

是否可以写一个re.sub,以便:

import re
s = "the blue dog and blue cat wore 7 blue hats 9 days ago"
p = re.compile(r'blue (?P<animal>dog|cat)|(?P<numberBelowSeven>[0-7])|(?P<numberNotSeven>[8-9])')

结果,

'the animal and animal wore numberBelowSeven blue hats numberNotSeven days ago"

奇怪的是,replace strings嘉豪和getting group names上有文档,但两者都没有详细记录的方法。

2 个答案:

答案 0 :(得分:1)

您可以使用返回re.sub with a callbackmatchobj.lastgroup

import re

s = "the blue dog and blue cat wore 7 blue hats 9 days ago"
p = re.compile(r'blue (?P<animal>dog|cat)|(?P<numberBelowSeven>[0-7])|(?P<numberNotSeven>[8-9])')

def callback(matchobj):
    return matchobj.lastgroup

result = p.sub(callback, s)
print(result)

产量

the animal and animal wore numberBelowSeven blue hats numberNotSeven days ago

请注意,如果您使用的是Pandas,则可以使用Series.str.replace

import pandas as pd

def callback(matchobj):
    return matchobj.lastgroup

df = pd.DataFrame({'foo':["the blue dog", "and blue cat wore 7 blue", "hats 9", 
                          "days ago"]})
pat = r'blue (?P<animal>dog|cat)|(?P<numberBelowSeven>[0-7])|(?P<numberNotSeven>[8-9])'
df['result'] = df['foo'].str.replace(pat, callback)
print(df)

产量

                        foo                                 result
0              the blue dog                             the animal
1  and blue cat wore 7 blue  and animal wore numberBelowSeven blue
2                    hats 9                    hats numberNotSeven
3                  days ago                               days ago

如果您有嵌套的命名组,则可能需要一个更复杂的回调,它会遍历matchobj.groupdict().items()以收集所有相关的组名:

import pandas as pd

def callback(matchobj):
    names = [groupname for groupname, matchstr in matchobj.groupdict().items()
             if matchstr is not None]
    names = sorted(names, key=lambda name: matchobj.span(name))
    result = ' '.join(names)
    return result

df = pd.DataFrame({'foo':["the blue dog", "and blue cat wore 7 blue", "hats 9", 
                          "days ago"]})

pat=r'blue (?P<animal>dog|cat)|(?P<numberItem>(?P<numberBelowSeven>[0-7])|(?P<numberNotSeven>[8-9]))'

# pat=r'(?P<someItem>blue (?P<animal>dog|cat)|(?P<numberBelowSeven>[0-7])|(?P<numberNotSeven>[8-9]))'

df['result'] = df['foo'].str.replace(pat, callback)
print(df)

产量

                        foo                                            result
0              the blue dog                                        the animal
1  and blue cat wore 7 blue  and animal wore numberItem numberBelowSeven blue
2                    hats 9                    hats numberItem numberNotSeven
3                  days ago                                          days ago

答案 1 :(得分:0)

为什么不多次拨打re.sub()

>>> s = re.sub(r"blue (dog|cat)", "animal", s)
>>> s = re.sub(r"\b[0-7]\b", "numberBelowSeven", s)
>>> s = re.sub(r"\b[8-9]\b", "numberNotSeven", s)
>>> s
'the animal and animal wore numberBelowSeven blue hats numberNotSeven days ago'

然后,您可以将其放入&#34;更改列表中。并逐一申请:

>>> changes = [
...     (re.compile(r"blue (dog|cat)"), "animal"),
...     (re.compile(r"\b[0-7]\b"), "numberBelowSeven"),
...     (re.compile(r"\b[8-9]\b"), "numberNotSeven")
... ]
>>> s = "the blue dog and blue cat wore 7 blue hats 9 days ago"
>>> for pattern, replacement in changes:
...     s = pattern.sub(replacement, s)
... 
>>> s
'the animal and animal wore numberBelowSeven blue hats numberNotSeven days ago'

请注意,我还添加了边界检查(\b)。