在文件中使用Python进行条件搜索和替换
我有一个超过10MB的大文本文件,需要进行条件搜索和替换。我想把文件中每个"a"替换成"ā",前提是"a"后面跟着的字符是"r"、"m"、"n"或"u"。
例如:
输入文件
Hamro sano ghar holata.
输出文件
Hāmro sāno ghār holata.
编辑
谢谢大家,看来这个方法效果不错。但它似乎对非拉丁字符,比如印度文字,不太管用:
针对拉丁字符的有效脚本:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import re
input = "Hamro sano ghar holata."
regex = re.compile(ur'a([rmnu])')
print regex.sub(ur'ā\1', input)
脚本1(用于天城文)不管用
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import re
input ="संगम"
regex = re.compile(ur'ं([कखगघ])')
print regex.sub(r'ङ्\1', input)
脚本2(添加了unicode内容)不管用
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import re
input =u"संगम"
regex = re.compile(ur'ं([कखगघ])', re.UNICODE)
print regex.sub(r'ङ्\1', input)
预期输出:把ं替换成ङ्,因为ग跟在ं后面,也就是सङ्गम
3 个回答
对于你那个大文本文件,建议先复制一份原文件,然后替换里面的字符,最后把更新后的内容写入一个新文件。你应该一次只读取一小部分,而不是一次性把整个文件都读进来。(虽然在现代电脑上,你可以一次性把10MB的文件都读进来。)
一个简单的方法是把文件对象当作一个迭代器使用;这样可以一次从文件中返回一行内容。
import re
pat = re.compile(ur'a([rmnu])') # pre-compile regex pattern for speed
f = open("corrected_file.txt", "wb")
for line in open("big_file_10mb.txt", "rb"):
line = pat.sub(ur'ā\1', line)
f.write(line)
f.close()
如果你想一次性把整个文件读进来,可以使用 .read()
方法:
f = open("big_file_10mb.txt", "rb")
s = f.read() # read entire file contents
f.close()
s = pat.sub(ur'ā\1', s) # replace over entire file contents
f = open("corrected_file.txt", "wb")
f.write(s) # write entire file contents
f.close(s)
不过,除非你有很好的理由,否则不要这样做。逐行读取的方式更容易理解,而且在文件很大的时候,相比于电脑的内存,这种方式效果更好。
书籍《Dive Into Python》中有一章专门讲解正则表达式:
http://diveintopython3.ep.io/regular-expressions.html
你需要读取Unicode并替换Unicode字符。你需要弄清楚文件的原始编码,先读取它,然后转换成Unicode,进行替换,最后再用正确的编码写出文件。或者你可以使用特殊的“codecs”模块;使用 codecs.open() 可以得到一个自动转换的文件对象。
这里有关于Python的Unicode使用文档:
http://docs.python.org/howto/unicode.html
假设你要读取的文本文件是用UTF-8编码的。我想这样做应该对你有帮助:
import codecs
import re
pat = re.compile(ur'a([rmnu])') # pre-compile regex pattern for speed
f = codecs.open("corrected_file.txt", mode="wb", encoding="utf-8")
for line in codecs.open("big_file_10mb.txt", mode="rb", encoding="utf-8"):
line = pat.sub(ur'ā\1', line)
f.write(line)
f.close()
在编程中,有时候我们会遇到一些问题,特别是在使用某些工具或库的时候。这些问题可能会让我们感到困惑,尤其是当我们刚开始学习编程的时候。比如,有人可能会在使用某个特定的功能时,发现它没有按照预期工作。这种情况下,理解问题的原因就变得非常重要。
通常,解决这些问题的方法是查看相关的文档或社区讨论,比如StackOverflow。这里有很多经验丰富的开发者分享他们的经验和解决方案。通过阅读这些内容,我们可以学习到如何处理类似的问题,避免在未来再次遇到同样的麻烦。
总之,编程的学习过程就是不断地解决问题和积累经验。遇到困难时,不要气馁,积极寻求帮助和资源,慢慢你就会变得更加熟练。
re.sub(r'a(?=[rmnu])',r'ā',"Hamro sano ghar holata.")
这里你需要一个简单的正则表达式。像这样吗?
>>> import re
>>> input = "Hamro sano ghar holata."
>>> regex = re.compile(ur'a([rmnu])') # the part in parens is remembered
>>> print regex.sub(ur'ā\1', input) # replace by ā plus remembered part
Hāmro sāno ghār holata.
补充说明:
先说说背景:
处理德瓦那加里(देवनागरी)文字要难得多,这不是因为编码的问题,而是因为这些字形组合的规则非常复杂(至少比拉丁字母要复杂得多)。比如,我现在在Chrome浏览器上写这个回答,但它依然不能正确显示“Devanāgarī”这个词(它把字母'e'的发音符号放错了地方——对于双元音'ai'也是如此)。
这些字形是如何组合在一起的,叫做“连字”,而对于德瓦那加里来说,从技术角度来看,这些连字非常复杂。如果再加上由sāndhi(संधि)引入的额外复杂性(同样,Chrome在显示代表anusvāra的bindu时也会放错位置),那么你会发现你想做的事情会变得极其困难。
不过,既然你遇到的问题仅限于这个简单的情况,我认为还是可以干净利落地解决的。
>>> import re
>>> inputString = u"संगम"
>>> regex = re.compile(ur'\u0902(?=[कखगघ])')
>>> print regex.sub(ur'ङ\u094d', inputString)
सङ्गम
在我使用的正则表达式中,我把anusvāra和virāma(印地语中的halant)替换成了Unicode转义值,以便更清晰。考虑到连字的工作方式,这样做可能会漏掉一些情况,但我把我的例子改成了使用前瞻(lookahead),就像@Kabie的例子那样(这可能是更好的选择),以尽量减少这个问题。