'\r' 在 Python `csv.writer()` 中不作为 `lineterminator`

'\r' not working as `lineterminator` within Python `csv.writer()`

我正在研究 Windows。我有一个 Python 文件来创建一个新的 CSV 文件,我使用 Notepad (even through Microsoft Excel).

查看它
import csv
data = [['fruit','quantity'], ['apple',5], ['banana',7],['mango',8]]
with open('d:\lineter.csv', 'w') as l:
    w = csv.writer(l,delimiter='|', lineterminator='\r')
    w.writerows(data)

记事本中生成的文件:

fruit|quantityapple|5banana|7mango|8

马车return\r行不行?它的工作方式类似于 Notepad 中的 lineterminator=''。但在 Excel 中,它的工作方式类似于 '\n'。

输出似乎没有实现回车 return。当我将 lineterminator 用作:

w = csv.writer(l, delimiter='|', lineterminator='*\r*\n')

记事本中的输出为:

fruit|quantity**
apple|5**
banana|7**
mango|8**

这里也很明显。

writer() 中的 lineterminator 中的 '\r' 是如何工作的? 还是那里发生了另一件事?

较短的答案:

何时使用回车 return(CR,\r)与换行(LF,\n)与两者(CRLF,\r\n) 在 Windows、Mac 和 Linux:

上的文本编辑器中显示一个新行

How does '\r' work in lineterminator in writer()??

它在 csv.writer() 中运行良好。这确实不是 Python、CSV 或编写器的问题。这是操作系统的历史差异(实际上,更准确地说是 program-specific difference)可以追溯到 1960 年代左右。

Or is there another thing happening there?

是的,就是这个。

您的记事本版本无法将回车符 return (\r) 识别为用于显示换行的字符,因此不会在记事本中这样显示。其他文本编辑器,例如 Sublime Text 3,即使在 Windows.

上也可能会

直到大约 2018 年左右,Windows 和记事本需要一个回车符 return + 换行符 (\r\n) 一起显示一个新行。将此与 Mac 和 Linux 进行对比,它们只需要 \n.

解决方案是在 Windows 上换行使用 \r\n,在 Mac 或 Linux 上换行单独使用 \n。您还可以尝试使用不同的文本编辑器,例如 Sublime Text,查看或编辑文本文件时,或者如果可能的话,升级您的 Windows 或记事本版本,因为 somewhere around the year 2018 Windows 记事本开始单独接受 \r 作为有效的 old-Mac-style 新行字符。

(来自 OP 在这个答案下的评论):

Then why to give '\r\n'???

当程序员编写程序时,程序员可以让程序做任何程序员想让程序做的事情。 当 Windows 程序员制作 Windows 和记事本时,他们决定让程序如果得到 \r 则什么也不做,如果得到 \n 则什么也不做,并且如果\r\n 在一起,则换行。就这么简单。该程序完全按照程序员的要求执行,因为他们决定这就是他们希望程序工作的方式。因此,如果您想在 Windows 中的旧版(2018 年之前)记事本中换行,则必须按照程序员的要求进行操作才能获得它。 \r\n是吗

这也可以追溯到 teletypewriters (read the "History" and "Representation" sections here), and this page about "teleprinters" / "teletypewriters" / "teletype or TTY machines" 时代:

A typewriter or electromechanical printer can print characters on paper, and execute operations such as move the carriage back to the left margin of the same line (carriage return), advance to the same column of the next line (line feed), and so on.
(source; emphasis added)

电传打字机上的机械托架 return 按钮(\r 现在在计算机上)意味着:“return 托架(打印头)到行首”(意思是:页面的最左侧),电传打字机上的换行机械装置(\n 现在在计算机上)意思是:“将纸张向上卷起一行,这样我们就可以在下一行打字了。 “如果没有机械换行 (\n) 操作,单独的托架 return (\r) 会将机械打印头移动到页面的最左侧并导致您 在你已经输入的字词上重新输入! 没有回车 return 机械动作(\r 在计算机上),换行机械动作(\n) 单独会导致您只需在页面上每一行的最右侧的最后一列中键入内容,再也无法 return 打印头再次移至页面左侧!在 electro-mechanical 电传打字机上,它们 both 必须被使用:托架 return 会将打印头带回打字机的左侧页,换行动作会将打印头向下移动到下一行因此,据推测,Windows 程序员认为保持这一传统是合乎逻辑的,他们决定要求 both a \r\n 一起 在计算机上创建一个新行,因为这是传统上必须在 electro-mechanical 电传打字机.

上完成的方式

阅读下文了解详情。

详细信息(较长的答案):

我对正在发生的事情有一些想法,但让我们来看看。我相信我们有两个问题需要回答:

  1. \r 是否实际存储到文件中?
  2. 记事本是否实际显示 \r,如果没有,为什么不显示?

所以,对于#1。让我们在 Linux Ubuntu 20.04(Focal Fossa)上进行测试:

这个程序:

#!/usr/bin/python3

import csv
data = [['fruit','quantity'], ['apple',5], ['banana',7],['mango',8]]
with open('d:\lineter.csv','w') as l:
    w = csv.writer(l, delimiter='|', lineterminator='\r')
    w.writerows(data)

生成此文件:d:\lineter.csv。如果我在 Sublime Text 3 text editor 中打开它,我会看到:

fruit|quantity
apple|5
banana|7
mango|8

到目前为止一切顺利。我们再看看命令行中带hexdump的字符:

hexdump -c显示了\r个字符,果然!

$ hexdump -c d\:\lineter.csv
0000000   f   r   u   i   t   |   q   u   a   n   t   i   t   y  \r   a
0000010   p   p   l   e   |   5  \r   b   a   n   a   n   a   |   7  \r
0000020   m   a   n   g   o   |   8  \r
0000028

您也可以使用 hexdump -C 来显示十六进制字符,同样,我在文件中看到 \r 作为十六进制 0d 字符,这是正确的。

好的,所以我在 Linux 中的 VirtualBox 虚拟机中启动 Windows 10 Professional,然后在记事本中打开相同的文件,并且......它也有效!见截图:

但是,请注意我圈出的部分,上面写着“Macintosh (CR)”。我是 运行 最新版本的 Windows 10 Professional。 我敢打赌您使用的是没有此修复程序的旧版记事本,您的记事本不会在这里说明。 这是因为对于 33年记事本d不要将 Carriage Return 或 \r 作为有效的 line-ending 处理,因此它不会这样显示。 请参阅此处:Windows Notepad fixed after 33 years: Now it finally handles Unix, Mac OS line endings .

由于 historical differences dating back to teletypewriters and Morse code (read the "History" and "Representation" sections here), different systems decided to make their text editors treat line endings in different ways. From the article just above(重点添加):

Notepad previously recognized only the Windows End of Line (EOL) characters, specifically Carriage Return (CR, \r, 0x0d) and Line Feed (LF, \n, 0x0a) together.

For old-school Mac OS, the EOL character is just Carriage Return (CR, \r, 0x0d) and for Linux/Unix it's just Line Feed (LF, \n, 0x0a). Modern macOS, since Mac OS X, follows the Unix convention.

所以,我们这里的内容是在文本编辑器中显示为换行符:

  1. Old-school Mac: 仅 CR (\r)
  2. Windows 直到 ~2018 年的记事本: CR 和 LF 一起(\r\n
  3. Linux: 仅 LF (\n)
  4. 现代 Mac: 仅限 LF (\n)
  5. 现代 Windows 记事本(年份 ~2018 及以后): 上述任何场景。

因此,对于 Windows,只需坚持 always 使用 \r\n 作为换行符,对于Mac 或 Linux,只要坚持始终使用 \n 作为换行符,除非您试图保证 old-school(即, pre-2019 :)) Windows 文件的兼容性,在这种情况下,您也应该使用 \r\n 作为换行符。


注意,对于 Sublime Text 3,我只是在 PreferencesSettings 中搜索了首选项,找到了这个设置:

    // Determines what character(s) are used to terminate each line in new files.
    // Valid values are 'system' (whatever the OS uses), 'windows' (CRLF) and
    // 'unix' (LF only).
    "default_line_ending": "system",

因此,要对任何 OS 使用 运行 Sublime Text 的约定,默认值为“系统”。但是,要在 Sublime Text 中编辑和保存文件时强制使用 'windows' (CRLF) 行结尾,请使用:

"default_line_ending": "windows",

并强制 Unix(Mac 和 Linux)LF-only 行结束设置,使用这个:

"default_line_ending": "unix",

在记事本编辑器中,我找不到可以配置的设置。它是一个简单的编辑器,已有 33 年的历史,仅用于 Windows 行结尾。

补充阅读:

  1. https://en.wikipedia.org/wiki/Teleprinter
  2. https://en.wikipedia.org/wiki/Newline#History
  3. Is a new line = \n OR \r\n?
  4. Why does Windows use CR LF?
  5. [我还需要读书学习]Unix & Linux: Why does Linux use LF as the newline character?
  6. [我还需要读书学习]Retrocomputing: Why is Windows using CR+LF and Unix just LF when Unix is the older system?