【问题标题】:Python restrict newline characters for readlines()Python 限制 readlines() 的换行符
【发布时间】:2015-03-04 15:25:55
【问题描述】:

我正在尝试拆分混合使用换行符LFCRLFNEL 的文本。我需要将NEL 字符排除在场景之外的最佳方法。

是否有一个选项可以指示readlines() 在拆分行时排除 NEL?我也许可以read() 并只匹配循环上的LFCRLF 分割点。

有没有更好的解决方案?

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

在使用 readlines() 时,它确实在 NEL 字符处分裂:

文件内容为:

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

【问题讨论】:

  • 什么是 NEL 字符?更准确地说 - 它的 ASCII/代码点值是多少?
  • NEL (U+0085) 不是 readlines() 支持的字符,据我所知。
  • 为什么不使用 read(1) 逐个字符处理?
  • @carl:因为它可能会慢很多。

标签: python python-2.7 readlines


【解决方案1】:

file.readlines() 只会拆分为 \n\r\r\n,具体取决于操作系统以及是否启用了通用换行支持。

U+0085 NEXT LINE (NEL) 在该上下文中未被识别为换行符,您无需执行任何特殊操作即可让file.readlines() 忽略它。

引用open() function documentation

Python 通常在构建时支持通用换行符;提供'U' 将文件作为文本文件打开,但行可能被以下任何一种终止:Unix 行尾约定'\n'、Macintosh 约定'\r' 或Windows 约定'\r\n'。所有这些外部表示都被 Python 程序视为'\n'。如果 Python 是在没有通用换行符的情况下构建的,则支持 'U' 的模式与普通文本模式相同。请注意,如此打开的文件对象还有一个名为 newlines 的属性,其值为 None(如果尚未看到换行符)、'\n''\r''\r\n',或包含所有看到的换行符类型的元组。

还有universal newlines glossary entry

一种解释文本流的方式,其中以下所有内容都被识别为结束行:Unix 行尾约定'\n'、Windows 约定'\r\n' 和旧的Macintosh 约定'\r'。有关其他用途,请参阅 PEP 278PEP 3116 以及 str.splitlines()

不幸的是,codecs.open() 违反了这条规则; documentation 含糊地暗示了被询问的特定编解码器:

行尾是使用编解码器的解码器方法实现的,如果 keepends 为真,则包含在列表条目中。

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

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

io 是全新的 I/O 基础架构,在 Python 3 中完全取代了 Python 2 系统。它只处理 \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() 的代码,其中has a documentation bug;拆分 unicode 字符串时,它将拆分 Unicode 标准认为是换行符的任何内容(即quite a complex issue)。这种方法的文档没有解释这一点;它声称只根据通用换行规则进行拆分。

【讨论】:

  • 我很荣幸您的回答提供了丰富的信息。但是,问题仍然没有解决。我不想删除 NEL 字符。我只是想在分割线时排除它。
  • @Gaudha:他们没有分开。他们不需要忽视。如果是,则您没有 NEL 字符。您能否向我们展示您的数据的repr() 表示形式?
  • @Gaudha:换句话说,请提供(在您的问题中)MCVE,您可以通过它来演示问题并解释预期结果。
  • "u'Line 1 \\x85 Line 1.1\\r\\nLine 2\\r\\nLine 3\\r\\n'"
  • @Gaudha:我现在有时间好好考虑一下了。 codecs.open() 确实在 U+0085 上分裂,而且这种行为充其量非常糟糕记录在案。请改用io.open(),我已将您链接到导致这种差异的关键的错误报告。
猜你喜欢
  • 2014-04-13
  • 2014-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-07
  • 2023-04-08
  • 1970-01-01
相关资源
最近更新 更多