我可以使用下面的代码创建一个新文件,使用正则表达式替换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
- > aa
,b
- > bb
和c
- > cc
。
所以我必须为我想要改变的所有字母写下那一行,或者是否有更简单的方法。也许要创建一个翻译的“字典”。我应该把这些字母放到一个数组中吗?如果我这样做,我不确定如何打电话给他们。
答案 0 :(得分:37)
@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)
因此,在您的情况下,您可以制作一个词典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)
我实际上在生产中使用了这种精确的方法,在这种情况下,我需要将一年中的几个月从捷克语翻译成英语,以进行网络抓取任务。
正如@nhahtdh所指出的,这种方法的一个缺点是它不是无前缀的:作为其他字典键前缀的字典键将导致该方法中断。
答案 1 :(得分:16)
您可以使用捕获组和反向引用:
re.sub(r"([characters])", r"\1\1", text.read())
将要加倍的字符放在[]
之间。对于小写a
,b
,c
:
re.sub(r"([abc])", r"\1\1", text.read())
在替换字符串中,您可以使用()
符号来引用捕获组\n
匹配的任何内容,其中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)
答案 2 :(得分: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'
答案 3 :(得分:2)
如果您的模式本身就是正则表达式,则其他解决方案均无效。
为此,您需要:
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)
可以用作:
>>> multi_sub([
... ('a+b', 'Ab'),
... ('b', 'B'),
... ('a+', 'A.'),
... ], "aabbaa") # matches as (aab)(b)(aa)
'AbBA.'
请注意,此解决方案不允许您将捕获组放在正则表达式中,或将其用于替换。
答案 4 :(得分:1)
您可以使用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))
修改后的文本是:
0 name is going to visit city in month
1 I was born in date
2 I will be there at time
您可以找到示例here
答案 5 :(得分:0)
我发现我必须通过将lambda函数更改为使用myDict.get(mo.group(1),mo.group(1))来修改Emmett J. Butler的代码。原始代码对我不起作用;如果找不到密钥,使用myDict.get()也可以提供默认值的好处。
OIDNameContraction = {
'Fucntion':'Func',
'operated':'Operated',
'Asist':'Assist',
'Detection':'Det',
'Control':'Ctrl',
'Function':'Func'
}
replacementDictRegex = re.compile("(%s)" % "|".join(map(re.escape, OIDNameContraction.keys())))
oidDescriptionStr = replacementDictRegex.sub(lambda mo:OIDNameContraction.get(mo.group(1),mo.group(1)), oidDescriptionStr)
答案 6 :(得分:0)
如果要处理文件,我有一个有关此问题的简单python代码。 更多信息here。
import re
def multiple_replace(dictionary, text):
# Create a regular expression from the dictionaryary keys
regex = re.compile("(%s)" % "|".join(map(re.escape, dictionary.keys())))
# For each match, look-up corresponding value in dictionaryary
String = lambda mo: dictionary[mo.string[mo.start():mo.end()]]
return regex.sub(String , text)
if __name__ == "__main__":
dictionary = {
"Wiley Online Library" : "Wiley",
"Chemical Society Reviews" : "Chem. Soc. Rev.",
}
with open ('LightBib.bib', 'r') as Bib_read:
with open ('Abbreviated.bib', 'w') as Bib_write:
read_lines = Bib_read.readlines()
for rows in read_lines:
#print(rows)
text = rows
new_text = multiple_replace(dictionary, text)
#print(new_text)
Bib_write.write(new_text)