起因
今天使用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的如下:
Windows的如下:
这里先说一下,十六进制0D
对应字符\r
,0A
对应字符\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'))
。因为是以二进制格式写入文件,所以写入的数据只能是以二进制的格式。因此我们需要将原本的字符串转换为二进制数据再进行写入。