我是Python的新手,我遇到了正则表达式问题。我正在尝试删除文本文件中每行末尾的换行符,但前提是它跟在小写字母后面,即[a-z]
。如果该行的结尾以小写字母结尾,我想用空格替换换行符/换行符。
这是我到目前为止所得到的:
import re
import sys
textout = open("output.txt","w")
textblock = open(sys.argv[1]).read()
textout.write(re.sub("[a-z]\z","[a-z] ", textblock, re.MULTILINE) )
textout.close()
答案 0 :(得分:23)
尝试
re.sub(r"(?<=[a-z])\r?\n"," ", textblock)
\Z
仅在字符串末尾匹配,在最后一个换行符后,所以它绝对不是您需要的。 Python正则表达式引擎无法识别\z
。
(?<=[a-z])
是positive lookbehind assertion,用于检查当前位置前的字符是否为小写ASCII字符。只有这样,正则表达式引擎才会尝试匹配换行符。
此外,始终使用带有正则表达式的原始字符串。使反斜杠更容易处理。
答案 1 :(得分:2)
作为一个替代答案,虽然它需要更多的行,但我认为以下可能更清楚,因为正则表达式更简单:
import re
import sys
with open(sys.argv[1]) as ifp:
with open("output.txt", "w") as ofp:
for line in ifp:
if re.search('[a-z]$',line):
ofp.write(line.rstrip("\n\r")+" ")
else:
ofp.write(line)
...这可以避免将整个文件加载到字符串中。如果你想使用更少的线条,但仍然避免积极的外观,你可以这样做:
import re
import sys
with open(sys.argv[1]) as ifp:
with open("output.txt", "w") as ofp:
for line in ifp:
ofp.write(re.sub('(?m)([a-z])[\r\n]+$','\\1 ',line))
该正则表达式的部分是:
(?m)
[打开多行匹配] ([a-z])
[匹配单个小写字符作为第一组] [\r\n]+
[匹配一个或多个回车或换行符,以涵盖\n
,\r\n
和\r
] $
[匹配字符串的结尾] ...如果匹配行,则小写字母和行结尾将替换为\\1
,小写字母后跟空格。
答案 2 :(得分:1)
我的观点是避免使用正面的lookbehind可能会使代码更具可读性
行。虽然,就个人而言,我发现它的可读性不高。这是一个品味问题。
在你的编辑中:
首先,(?m)是没有必要的,因为 for ifp中的行:一次选择一行,因此只有一行换行每行的结尾
其次,放置 $ ,没有效用,因为它总是匹配字符串行的结尾。
任何方式,采用你的观点,我发现了两种方式来避免看到后面的断言:
with open(sys.argv[1]) as ifp:
with open("output.txt", "w") as ofp:
for line in ifp:
ante_newline,lower_last = re.match('(.*?([a-z])?$)',line).groups()
ofp.write(ante_newline+' ' if lower_last else line)
和
with open(sys.argv[1]) as ifp:
with open("output.txt", "w") as ofp:
for line in ifp:
ofp.write(line.strip('\r\n')+' ' if re.search('[a-z]$',line) else line)
第二个更好:只有一行,一个简单的匹配测试,不需要groups(),自然逻辑
编辑:哦,我意识到第二个代码只是你在第一行重写的代码,Longair