Python限制readlines()函数中的换行符

3

我正在尝试拆分一个包含混合换行符LFCRLFNEL的文本。我需要最佳方法将NEL字符排除在外。

是否有选项可以指示readlines()在拆分行时排除NEL?我可以使用循环仅匹配LFCRLF拆分点来实现read()

还有更好的解决方案吗?

我使用codecs.open()打开utf-8文本文件。

在使用readlines()时,它确实会在NEL字符处进行拆分:

session screenshot

文件内容如下:

"u'Line 1 \\x85 Line 1.1\\r\\nLine 2\\r\\nLine 3\\r\\n'"

什么是NEL字符?更准确地说,它的ASCII/代码点值是多少? - ErikR
据我所知,NEL(U+0085)不是readlines()支持的字符。 - Martijn Pieters
@user5402:http://codepoints.net/U+0085 - Martijn Pieters
为什么不直接使用read(1)逐字符处理呢? - Carl Houtman
2
@carl:因为这样很可能会变得更慢。 - martineau
显示剩余2条评论
2个回答

9

file.readlines() 只会在操作系统支持通用换行符时,根据 \n\r\r\n 进行拆分。

U+0085 NEXT LINE (NEL) 在这种情况下不被视为换行符,因此您无需采取任何特殊措施使 file.readlines() 忽略它。

引用 open() 函数文档

Python通常支持通用换行符; 提供'U'将文件打开为文本文件,但行可能以以下任何一种方式终止: Unix行末约定'\n'、Macintosh约定'\r'或Windows约定'\r\n'。 所有这些外部表示均被Python程序视为'\n'。 如果Python没有使用通用换行符支持,则带'U'的模式与普通文本模式相同。 请注意,因此打开的文件对象还具有名为newlines的属性,该属性的值为None(如果尚未看到换行符),'\n''\r''\r\n'或包含所有已看到的换行符类型的元组。
通用换行符词汇表条目:
一种解释文本流的方式,其中以下所有内容都被认为是结束行:Unix换行约定'\n',Windows约定'\r\n'和旧Macintosh约定'\r'。请参见PEP 278PEP 3116,以及str.splitlines()用于附加使用。不幸的是,codecs.open()违反了这个规则; 文档模糊地提到了所请求的特定编解码器:行结束符是使用编解码器的解码器方法实现的,如果keepends为真,则包括在列表条目中。

使用io.open()代替codecs.open(),以正确的编码打开文件,然后逐行处理:

with io.open(filename, encoding=correct_encoding) as f:
    lines = f.open()

io 是 Python 3 中完全替代 Python 2 系统的新 I/O 基础设施。它仅处理 \n\r\r\n

>>> open('/tmp/test.txt', 'wb').write(u'Line 1 \x85 Line 1.1\r\nLine 2\r\nLine 3\r\n'.encode('utf8'))
>>> import codecs
>>> codecs.open('/tmp/test.txt', encoding='utf8').readlines()
[u'Line 1 \x85', u' Line 1.1\r\n', u'Line 2\r\n', u'Line 3\r\n']
>>> import io
>>> io.open('/tmp/test.txt', encoding='utf8').readlines()
[u'Line 1 \x85 Line 1.1\n', u'Line 2\n', u'Line 3\n']
codecs.open() 的结果是由于代码使用了 str.splitlines(),而该方法存在文档错误;当分割 Unicode 字符串时,它会根据 Unicode 标准认为的任何换行符进行分割(这是一个相当复杂的问题quite a complex issue)。该方法的文档未能充分解释这一点;它声称仅按照通用换行规则进行分割。has a documentation bug

我尊重您的答案,它很有信息量。但是问题仍未解决。我不想删除NEL字符。我只想在拆分行时将其排除在外。 - Gaudha
@Gaudha:它们没有被分割。它们不需要被忽略。如果它们被忽略了,那么你的数据中就没有NEL字符。你能给我们展示一下你的数据的repr()表示吗? - Martijn Pieters
1
@Gaudha:换句话说,请在你的问题中提供一个 MCVE,通过它你可以演示问题并解释预期的结果。 - Martijn Pieters
"u'Line 1 \\x85 Line 1.1\\r\\nLine 2\\r\\nLine 3\\r\\n'" - Gaudha
@Gaudha,没错,codecs.open() 产生的文件对象会在NEL上分割。这是无法配置的。io.open() 是否也会这样?如果是的话,请使用常规的 open() 并解码每一行 ([line.decode('utf8') for line in open(filename)])。我会在明天探索更多选项。 - Martijn Pieters
2
@Gaudha:我现在有时间来仔细研究这个问题了。codecs.open()确实是在U+0085上分割的,而且这种行为最多只能说是文档非常糟糕。相反,请使用io.open(),我已经将与此差异相关的错误报告链接给您了。 - Martijn Pieters

0
import re

f = [re.sub(' \\r ', '', str(line)) for line in open('file.csv', 'rb')]

将创建一个字符串列表,该列表将忽略额外的\r字符。列表中的每个元素都将是文件中的一行。我遇到了类似的问题,这在我的csv上起作用。您可能需要更改re.sub部分中的正则表达式以适应您的需求。

注意:这将摆脱\r字符并将其替换为''。我想要摆脱它们,所以对我有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接