使用StringIO和csv模块的通用换行模式的意外行为

Tim*_*ker 4 python csv newline python-3.x

请考虑以下内容(Windows下的Python 3.2):

>>> import io
>>> import csv
>>> output = io.StringIO()         # default parameter newline=None
>>> csvdata = [1, 'a', 'Whoa!\nNewlines!']
>>> writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
>>> writer.writerow(csvdata)
25
>>> output.getvalue()
'1,"a","Whoa!\nNewlines!"\r\n'
Run Code Online (Sandbox Code Playgroud)

为什么有一个\n- 不应该已经转换为\r\n自启用通用换行模式?

启用此功能,在输入,线路的结局\n,\r\r\n 将被转换为\n被返回给调用者之前.相反,在输出时,\n转换为系统默认行分隔符,os.linesep.

Joh*_*hin 6

"单个" \n作为第三个字段内的数据字符出现.因此,引用该字段以便csv读取器将其视为数据的一部分.它不是"行终止符"(应该称为行分隔符)或其中的一部分.为了更好地了解报价,请删除quoting=csv.QUOTE_NONNUMERIC.

\r\n之所以产生,是因为csv终止了dialect.lineterminator其默认值为的行\r\n.换句话说,忽略"通用换行符"设置.

更新

io.StringIO就新 arg而言,2.7和3.2文档实际上是相同的.

newline参数的工作方式与TextIOWrapper类似.默认情况下不进行换行.

我们将检查下面的第一句话.第二句适用于输出,具体取决于您对"默认"和"换行符"的解释.

TextIOWrapper文档:

换行可以是None,'','\n','\ r'或'\ r \n'.它控制行结尾的处理.如果为None,则启用通用换行符.与此启用,在输入时,行结尾"\n","\ r",或"\ r\N"被返回给调用者之前被转换为"\n".相反,在输出时,'\n'被转换为系统默认行分隔符os.linesep.如果换行符是其合法值的任何其他值,则在读取文件时该换行符将成为换行符,并且返回未换行符.输出时,'\n'将转换为换行符.

Windows上的Python 3.2:

>>> from io import StringIO as S
>>> import os
>>> print(repr(os.linesep))
'\r\n'
>>> ss = [S()] + [S(newline=nl) for nl in (None, '', '\n', '\r', '\r\n')]
>>> for x, s in enumerate(ss):
...     m = s.write('foo\nbar\rzot\r\n')
...     v = s.getvalue()
...     print(x, m, len(v), repr(v))
...
0 13 13 'foo\nbar\rzot\r\n'
1 13 12 'foo\nbar\nzot\n'
2 13 13 'foo\nbar\rzot\r\n'
3 13 13 'foo\nbar\rzot\r\n'
4 13 13 'foo\rbar\rzot\r\r'
5 13 15 'foo\r\nbar\rzot\r\r\n'
>>>
Run Code Online (Sandbox Code Playgroud)

第0行显示没有newlinearg 的"默认"不涉及\n(或任何其他字符)的转换.它当然不会转换'\n'os.linesep

第1行显示你得到的东西newline=None(应该与第0行相同,不应该吗?)实际上是INPUT通用换行符 - 奇怪!

第2行:newline=''没有变化,就像第0行一样.它肯定不会转换'\n'''.

第3,4和5行:正如文档所说,'\n'被转换为newlinearg 的值.

等效的Python 2.X代码与Python 2.7.2产生相同的结果.

更新2为了与内置程序保持一致open(),默认值应为os.linesep,如文档所述.要获得无翻译输出行为,请使用newline=''.注意:open()文档更清晰.我明天会提交错误报告.