14

我是 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()
4

3 回答 3

25

尝试

re.sub(r"(?<=[a-z])\r?\n"," ", textblock)

\Z仅在最后一个换行符之后的字符串末尾匹配,所以这绝对不是你需要的。\zPython 正则表达式引擎无法识别。

(?<=[a-z])是一个肯定的后向断言,它检查当前位置之前的字符是否是小写的 ASCII 字符。只有这样,正则表达式引擎才会尝试匹配换行符。

此外,始终使用带有正则表达式的原始字符串。使反斜杠更容易处理。

于 2011-02-22T07:28:45.567 回答
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,这将是小写字母后跟一个空格。

于 2011-02-22T07:46:11.810 回答
1

我的观点是避免使用积极的后视可能会使代码更具可读性

好的。不过,就我个人而言,我认为它的可读性并没有降低。这是一个品味问题。

在您的编辑中:

  • 首先, (?m)不是必需的,因为ifp 中的 for line:一次选择一行,因此每行字符串的末尾只有一个换行符

  • 其次,$因为它被放置,没有实用性,因为它总是匹配字符串行的结尾。

无论如何,采用您的观点,我找到了两种避免后视断言的方式:

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

于 2011-02-22T10:49:26.907 回答