我想通过Windows CMD(控制台)从Python管道带有类似unix的EOL(LF)文本。但是,Python似乎会自动将单个换行符转换为Windows样式的end-of-line (EOL)字符(即\r\n
,<CR><LF>
,0D 0A
,13 10
):
#!python3
#coding=utf-8
import sys
print(sys.version)
print("one\ntwo")
# run as py t.py > t.txt
结果
3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit (AMD64)]
one
two
或以十六进制... 6F 6E 65 0D 0A 74 77 6F 0D 0A
第二个EOL是因为
print()
默认为end='\n'
,但也会进行转换。
没有newline
参数或属性可供打印,就像open()
一样,那么如何控制呢?
答案 0 :(得分:1)
请参阅此回答: https://stackoverflow.com/a/34997357/1619432
print()
通常会写入sys.stdout
。以下是非交互模式的文档摘录:
stdout用于print()
的输出
sys.stdout:解释器用于标准...输出的文件对象
这些流是常规文本文件,类似于open()函数返回的文件。
Windows上的字符编码是ANSI
标准流是......像常规文本文件一样进行块缓冲。
请注意
要从/向标准流写入或读取二进制数据,请使用 底层二进制缓冲对象。例如,要将字节写入stdout, 使用sys.stdout.buffer.write(b'abc')。
让我们先尝试这种直接的方法:
import sys
print("one\ntwo")
sys.stdout.write('three\nfour')
sys.stdout.buffer.write(b'five\nsix')
结果
five\n
sixone\r\n
two\r\n
three\r\n
four
缓冲区写入似乎可以正常工作,尽管它会“混乱”输出顺序。
直接写入缓冲区之前刷新有助于:
import sys
print("one\ntwo")
sys.stdout.write('three\nfour')
sys.stdout.flush()
sys.stdout.buffer.write(b'five\nsix')
结果
one\r\n
two\r\n
three\r\n
fourfive\n
six
但它仍然没有“修复”print()。返回文件对象/流/文本文件(IO objects in Python Data model上的简短信息):
https://docs.python.org/3/glossary.html#term-text-file
能够读写str对象的文件对象。通常,文本文件实际上访问面向字节的数据流并自动处理文本编码。文本文件的示例是以文本模式('r'或'w'),sys.stdin,sys.stdout和io.StringIO实例打开的文件。
那么(如何)可以重新配置或重新打开sys.stdout 文件来控制换行行为?到底是什么?
>>> import sys
>>> type(sys.stdout)
<class '_io.TextIOWrapper'>
换行符控制行结尾的处理方式。它可以是None,'', '\ n','\ r'和'\ r \ n'。
它的工作原理如下:
从流中读取输入时,如果换行为“无”,则启用通用换行模式。 输入中的行可以以'\ n','\ r'或'\ r \ n'结尾,并且在返回给调用者之前将这些行转换为'\ n'。
如果是'',则启用通用换行模式,但行结尾将返回给调用者未翻译 如果它具有任何其他合法值,则输入行仅由给定字符串终止,并且行结尾将返回给未调用的调用者。当写入输出到流时,如果换行为无,则写入的任何'\ n'字符都会转换为系统默认行分隔符, os。 linesep 即可。
如果换行符为''或'\ n',则不进行翻译 如果换行符是任何其他合法值,则写入的任何“\ n”字符都将转换为给定的字符串。
让我们看看:
>>> sys.stdout.newline = "\n"
>>>
好的,那么
import sys
sys.stdout.newline = '\n'
print("one\ntwo")
不起作用:
one\r\n
two\r\n
因为该属性不存在:
>>> sys.stdout.newline
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: '_io.TextIOWrapper' object has no attribute 'newline'
我之前应该检查过..
>>> vars(sys.stdout)
{'mode': 'w'}
实际上,我们没有重新定义的newline
属性。
有用的方法吗?
>>> dir(sys.stdout)
['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', '__dict__',
'__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__',
'__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__iter__', '__le__', '__lt__',
'__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable',
'_finalizing', 'buffer', 'close', 'closed', 'detach', 'encoding',
'errors', 'fileno', 'flush', 'isatty', 'line_buffering', 'mode',
'name', 'newlines', 'read', 'readable', 'readline', 'readlines',
'seek', 'seekable', 'tell', 'truncate', 'writable', 'write',
'writelines']
不是。
但我们至少可以将缓冲区的默认接口替换为指定所需的换行符:
import sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, newline='\n' )
print("one\ntwo")
最终导致
one\n
two\n
要恢复,只需将 sys.stdout
重新分配给您制作的副本即可。或者,显然不推荐使用内部保留sys.__stdout__
来做到这一点。
警告:请参阅下面的eryksun
's comment,这需要一些小心。请改用他的解决方案(链接如下):
似乎也可以重新打开该文件,请参阅Wrap an open stream with io.TextIOWrapper获取灵感,并获得此答案https://stackoverflow.com/a/34997357/1619432。
如果你想仔细看看,请查看Python(CPython)来源: https://github.com/python/cpython/blob/master/Modules/_io/textio.c
还有os.linesep,让我们看看它是否真的是“\ r \ n”for Windows:
>>> import os
>>> os.linesep
'\r\n'
>>> ",".join([f'0x{ord(c):X}' for c in os.linesep])
'0xD,0xA'
这可以重新定义吗?
#!python3
#coding=utf-8
import sys, os
saved = os.linesep
os.linesep = '\n'
print(os.linesep)
print("one\ntwo")
os.linesep = saved
它可以在交互模式下,但显然不是这样:
\r\n
\r\n
one\r\n
two\r\n