如何在python中使用正则表达式进行多次替换?

Eur*_*e01 30 python regex string

我可以用下面这段代码来创建的替代一个新的文件aaa使用正则表达式.

import re

with open("notes.txt") as text:
    new_text = re.sub("a", "aa", text.read())
    with open("notes2.txt", "w") as result:
        result.write(new_text)
Run Code Online (Sandbox Code Playgroud)

我想知道我是否必须使用这一行,new_text = re.sub("a", "aa", text.read())多次但是将字符串替换为我要更改的其他字母,以便在我的文本中更改多个字母?

也就是说,所以a- > aa,b- > bbc- > cc.

所以我必须为我要改变的所有字母写下那一行,或者有一种更简单的方法.也许要创建一个翻译的"字典".我应该把这些字母放到一个数组中吗?如果我这样做,我不确定如何打电话给他们.

Emm*_*ler 42

@nhahtdh提出的答案是有效的,但我认为pythonic不如规范的例子,它使用的代码比他的正则表达式操作更不透明,并利用python的内置数据结构和匿名函数功能.

在这种情况下,翻译词典是有意义的.事实上,这就是Python Cookbook的用法,如本例所示(从ActiveState复制http://code.activestate.com/recipes/81330-single-pass-multiple-replace/)

import re 

def multiple_replace(dict, text):
  # Create a regular expression  from the dictionary keys
  regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))

  # For each match, look-up corresponding value in dictionary
  return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text) 

if __name__ == "__main__": 

  text = "Larry Wall is the creator of Perl"

  dict = {
    "Larry Wall" : "Guido van Rossum",
    "creator" : "Benevolent Dictator for Life",
    "Perl" : "Python",
  } 

  print multiple_replace(dict, text)
Run Code Online (Sandbox Code Playgroud)

因此,在您的情况下,您可以创建一个字典trans = {"a": "aa", "b": "bb"},然后将其multiple_replace与您要翻译的文本一起传递.基本上所有这个函数都在创建一个包含所有要翻译的正则表达式的巨大正则表达式,然后在找到一个正则表达式时,传递一个lambda函数regex.sub来执行翻译字典查找.

您可以在从文件中读取时使用此功能,例如:

with open("notes.txt") as text:
    new_text = multiple_replace(replacements, text.read())
with open("notes2.txt", "w") as result:
    result.write(new_text)
Run Code Online (Sandbox Code Playgroud)

我实际上已经在生产中使用了这种精确的方法,在这种情况下,我需要将一年中的几个月从捷克语翻译成英语,以进行网络抓取任务.

正如@nhahtdh所指出的,这种方法的一个缺点是它不是无前缀的:作为其他字典键前缀的字典键将导致该方法中断.

  • 您当前的解决方案尚未针对存在一对词的用例进行配置,其中一个词是另一个词的前缀。交替事项中的出现顺序。我认为至少你应该陈述这个假设。 (2认同)
  • 我无法让 re:I 在这种情况下工作(根据 @nhahtdh 的建议) Penny:我看不出在这种情况下如何使用通配符。我试过没有成功。 (2认同)
  • @thescoop:用你的代码提出一个新问题。如果你想在映射中使用正则表达式,你需要重写函数以删除编译中的 re.escape 并更改自定义替换函数以查找哪个组负责匹配并查找相应的替换(在这种情况下,输入应该是一个元组数组而不是 dict)。 (2认同)

nha*_*tdh 17

您可以使用捕获组和反向引用:

re.sub(r"([characters])", r"\1\1", text.read())
Run Code Online (Sandbox Code Playgroud)

把你想要翻倍的字符放在两者之间[].对于较低的情况下的情况下a,b,c:

re.sub(r"([abc])", r"\1\1", text.read())
Run Code Online (Sandbox Code Playgroud)

在替换字符串中,您可以()使用\n符号表示捕获组匹配的任何内容,其中n包含一些整数(0除外).\1是指第一个捕获组.还有另一种表示法\g<n>,其中n可以是任何非负整数(0允许); \g<0>将引用表达式匹配的整个文本.


如果要将除新行之外的所有字符加倍:

re.sub(r"(.)", r"\1\1", text.read())
Run Code Online (Sandbox Code Playgroud)

如果你想加倍所有字符(包括新行):

re.sub(r"(.)", r"\1\1", text.read(), 0, re.S)
Run Code Online (Sandbox Code Playgroud)


Geo*_*pis 9

您可以使用pandas库和replace函数。我用五个替换来代表一个例子:

df = pd.DataFrame({'text': ['Billy is going to visit Rome in November', 'I was born in 10/10/2010', 'I will be there at 20:00']})

to_replace=['Billy','Rome','January|February|March|April|May|June|July|August|September|October|November|December', '\d{2}:\d{2}', '\d{2}/\d{2}/\d{4}']
replace_with=['name','city','month','time', 'date']

print(df.text.replace(to_replace, replace_with, regex=True))
Run Code Online (Sandbox Code Playgroud)

修改后的文字是:

0    name is going to visit city in month
1                      I was born in date
2                 I will be there at time
Run Code Online (Sandbox Code Playgroud)

您可以在这里找到示例


小智 6

使用如何创建“字符串”类的技巧,我们可以使一个对象与字符串相同,但需要一个额外的sub方法:

import re
class Substitutable(str):
  def __new__(cls, *args, **kwargs):
    newobj = str.__new__(cls, *args, **kwargs)
    newobj.sub = lambda fro,to: Substitutable(re.sub(fro, to, newobj))
    return newobj
Run Code Online (Sandbox Code Playgroud)

这允许使用构建器模式,它看起来更好,但仅适用于预定数量的替换。如果您在循环中使用它,则不再需要创建额外的类。例如

>>> h = Substitutable('horse')
>>> h
'horse'
>>> h.sub('h', 'f')
'forse'
>>> h.sub('h', 'f').sub('f','h')
'horse'
Run Code Online (Sandbox Code Playgroud)


Eri*_*ric 5

如果您的模式本身是正则表达式,则其他任何解决方案都不起作用。

为此,您需要:

def multi_sub(pairs, s):
    def repl_func(m):
        # only one group will be present, use the corresponding match
        return next(
            repl
            for (patt, repl), group in zip(pairs, m.groups())
            if group is not None
        )
    pattern = '|'.join("({})".format(patt) for patt, _ in pairs)
    return re.sub(pattern, repl_func, s)
Run Code Online (Sandbox Code Playgroud)

可以用作:

>>> multi_sub([
...     ('a+b', 'Ab'),
...     ('b', 'B'),
...     ('a+', 'A.'),
... ], "aabbaa")  # matches as (aab)(b)(aa)
'AbBA.'
Run Code Online (Sandbox Code Playgroud)

请注意,此解决方案不允许您在正则表达式中放置捕获组,或在替换中使用它们。