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

2024-04-23 07:34:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我可以使用下面的代码创建一个新文件,使用正则表达式将a替换为aa

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)

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

也就是说,a-->;aab-->;bbc-->;cc

所以我必须为所有我想更改的字母写这行字,或者有更简单的方法。也许是为了编一本翻译词典。我应该把那些信排成一列吗?我不知道如果我去的话怎么去拜访他们。


Tags: 文件代码textimportgtretxtnew
3条回答

使用how to make a 'stringy' class中的提示,我们可以使一个对象与一个字符串相同,但对于一个额外的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

这允许使用构建器模式,它看起来更好,但只适用于预先确定的替换数量。如果在循环中使用它,就没有必要再创建额外的类了。E、 g

>>> h = Substitutable('horse')
>>> h
'horse'
>>> h.sub('h', 'f')
'forse'
>>> h.sub('h', 'f').sub('f','h')
'horse'

@nhahtdh提出的答案是正确的,但我认为比规范示例更少的pythonic,规范示例使用比regex操作更少不透明的代码,并利用了python的内置数据结构和匿名函数特性。

在这种情况下,翻译词典是有意义的。实际上,Python食谱就是这样做的,如本例所示(从ActiveStatehttp://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)

所以在你的例子中,你可以做一个dicttrans = {"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)

实际上,我在制作中使用了这种精确的方法,在这种情况下,我需要将一年中的几个月从捷克语翻译成英语来完成一个网页抓取任务。

正如@nhahtdh指出的,这种方法的一个缺点是它没有前缀自由:作为其他字典键前缀的字典键将导致方法中断。

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

re.sub(r"([characters])", r"\1\1", text.read())

[]之间放置要加倍的字符。对于小写abc

re.sub(r"([abc])", r"\1\1", text.read())

在替换字符串中,可以引用与捕获组()匹配的任何内容,其中n是一些正的整数(不包括0)。\1指第一个捕获组。还有另一个符号\g<n>,其中n可以是任何非负整数(允许为0);\g<0>将引用与表达式匹配的整个文本。


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

re.sub(r"(.)", r"\1\1", text.read())

如果要将所有字符(包括新行)加倍:

re.sub(r"(.)", r"\1\1", text.read(), 0, re.S)

相关问题 更多 >