起因

今天使用python生成的题目样例时,出现了字符串匹配有误的问题。
经过长达几个小时的排查后,最终确定是python的换行回车的问题。


正题

with open('a.txt','w') as f:
    for i in range(10):
        f.write(str(i) + '\n')

请看此代码,问:运行了该脚本后,a.txt文件的内容会变成什么?

你可能会说当然就是

0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n

咯,即

0
1
2
3
4
5
6
7
8
9

其实对,但并不是完全对。

如果你是在Linux上运行脚本,那么你这么说没问题。
但如果你是在Windows上运行脚本,那么情况则会有所不同了。

分析

我们使用二进制查看工具具体看一下Linux系统和Windows系统中输出的文件a.txt的异同。

Linux的如下:

python中的识别回车 python判断回车_python中的识别回车


Windows的如下:

python中的识别回车 python判断回车_linux_02


这里先说一下,十六进制0D对应字符\r0A对应字符\n

可以看出,在linux中,文件的内容的确如前面所说,是

0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n

,而在windows中,文件的内容却会在每个\n前面多一个\r。变成

0\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n

造成这种情况,是因为python3中open函数的w模式是文本只写模式,用w模式写入文件类似于在记事本里手动输入数据。
而在unix和windows以及Mac系统中,文件的换行有所不同。

  • 在Unix系统中,文件中一行的结束为\n
  • 在Windows系统中,文件中一行的结束为\r\n
  • 在Mac系统中,文件中一行的结束为\r

在Windows中,\r称为回车号,会将光标回退到当前行行首。
\n称为换行符,将光标移动到下一行(不会回到行首)。

解决方案

在Windows中使用python3open的w模式写入文件,会在每一个\n前面自动增加一个\r,使得最终的输出结果并非我们所期望的。要处理\r的问题,有以下两种比较简单的方法。

一、使用doc2unix命令

doc2unxi命令是Linux下的命令,是专门用来解决Windows编辑的文件中出现\r的问题的。调用此命令后,会将对应文件中的\r\n替换成\n
使用方法如下:

doc2unix 文件名

如:

doc2unix a.txt

在linux中调用此命令后,会将a.txt文件中的\r\n做替换。

二、使用wb模式写入文件

python3的open方法有一个wb模式,是以二进制格式只写方式打开一个文件。wb模式在使用python3爬虫下载文件的时候用得比较多。
使用二进制格式写入,会将原本的数据分毫不差地写入,避免了w模式中\n前面会自动增加\r的问题。
代码修改如下:

with open('a.txt','wb') as f:
    for i in range(10):
        f.write(str(str(i) + '\n').encode(encoding='utf-8'))

这里需要提到一点,使用wb模式写入文件时,需要将原本的f.write(str(i) + '\n')改成f.write(str(str(i) + '\n').encode(encoding='utf-8'))。因为是以二进制格式写入文件,所以写入的数据只能是以二进制的格式。因此我们需要将原本的字符串转换为二进制数据再进行写入。