来自通过raw_input()传递的文件内容副本中CR消失的奇怪现象

-3 投票
2 回答
788 浏览
提问于 2025-04-16 12:11

我在试图搞清楚一个看起来像是bug的原因时,发现了Python 2.7中raw_input()函数的一个奇怪行为:

它会把从文件内容手动复制(通过剪贴板)得到的字符串中的CR字符(回车符)去掉,但那些显示出来的、和之前相同的字符串传给raw_input()时却不会丢失CR字符。单独的CR字符在所有情况下都保持不变。这里的CR(回车符)就是\r这个字符。

为了更清楚地说明这个问题,这里有段代码,描述了要做什么才能观察到这个现象,只需要执行这些命令就可以了。

关键在于Text对象:它有7个字符,而传给raw_input()的却是8个字符来创建Text

为了验证传给raw_input()的参数确实有8个字符,我又创建了一个名为PASTED.txt的文件,里面放了同样的内容。要确认这个问题真的很麻烦,因为在Notepad++窗口中复制时,各种换行符(\r, \n, \r\n)在窗口的行末显示为CR LF

建议使用Ctrl-A来选择整个文件的数据。

我现在很困惑,不知道是我编码或理解上出了错,还是这是Python的一个真实特性。

希望能得到你们的评论和指点。

with open('PRIM.txt','wb') as f:
    f.write('A\rB\nC\r\nD')
print "  1) A file with name 'PRIM.txt' has just been created with content A\\rB\\nC\\r\\nD"
raw_input("  Open this file and copy manually its CONTENT in the clipboard.\n"+\
          "    --when done, press Enter to continue-- ")


print "\n  2) Paste this CONTENT in a Notepad++ window "+\
      "     and see the symbols at the extremities of the lines."
raw_input("    --when done, press Enter to continue-- ")


Text = raw_input("\n  3) Paste this CONTENT here and press a key : ")
print ("     An object Text has just been created with this pasted value of CONTENT.")


with open('PASTED.txt','wb') as f:
    f.write('')
print "\n  4) An empty file 'PASTED.txt' has just been created."
print "     Paste manually in this file the PRIM's CONTENT and shut this file."
raw_input("     --when done, press Enter to continue-- ")


print "\n  5) Enter the copy of this display of A\\rB\\nC\\r\\nD : \nA\rB\nC\r\nD"
DSP = raw_input('please, enter it on the following line :\n')
print "    An object DSP has just been created with this pasted value of this copied display"


print '\n----------'
with open('PRIM.txt','rb') as fv:
    verif = fv.read()
print "The read content of the file 'PRIM.txt' obtained by open() and read() : "+repr(verif)
print "len of the read content of the file 'PRIM.txt'  ==",len(verif)


print '\n----------'
print "The file PASTED.txt received by pasting the manually copied CONTENT of PRIM.txt"
with open('PASTED.txt','rb') as f:
    cpd = f.read()
    print "The read content of the file 'PASTED.txt' obtained by open() and read() "+\
          "is now : "+repr(cpd)
    print "its len is==",len(cpd)


print '\n----------'
print 'The object Text received through raw_input() the manually copied CONTENT of PRIM.txt'
print "value of Text=="+repr(Text)+\
      "\nText.split('\\r\\n')==",Text.split('\r\n')
print 'len of Text==',len(Text)


print '\n----------'
print "The object DSP received  through raw_input() the copy of the display of A\\rB\\nC\\r\\nD" 
print "value of DSP==",repr(DSP)
print 'len of DSP==',len(DSP)

我的操作系统是Windows。我想知道在其他操作系统上是否也会出现同样的情况。

2 个回答

0

在我发帖之后,我抬起头来看了下我的代码,确实注意到从文件中复制的数据在传给raw_input()时的修改,和Python直接从文件读取数据时对换行符的处理是一样的,这里有证据:

with open("TestWindows.txt", 'wb') as f:
    f.write("PACIFIC \r  ARCTIC \n  ATLANTIC \r\n  ")

print "\n- Following string have been written in TestWindows.txt in mode 'wb' :\n"+\
      "PACIFIC \\r  ARCTIC \\n  ATLANTIC \\r\\n  "


print "\n- data got by reading the file TestWindows.txt in 'rb' mode :"
with open("TestWindows.txt", 'rb') as f:
    print "    repr(data)==",repr(f.read())

print "\n- data got by reading the file TestWindows.txt in 'r' mode :"
with open("TestWindows.txt", 'r') as f:
    print "    repr(data)==",repr(f.read())

print "\n- data got by reading the file TestWindows.txt in 'rU' mode :"
with open("TestWindows.txt", 'rU') as f:
    print "    repr(data)==",repr(f.read())

结果:

- Following string have been written in TestWindows.txt in mode 'wb' :
PACIFIC \r  ARCTIC \n  ATLANTIC \r\n  

- data got by reading the file TestWindows.txt in 'rb' mode :
    repr(data)== 'PACIFIC \r  ARCTIC \n  ATLANTIC \r\n  '

- data got by reading the file TestWindows.txt in 'r' mode :
    repr(data)== 'PACIFIC \r  ARCTIC \n  ATLANTIC \n  '

- data got by reading the file TestWindows.txt in 'rU' mode :
    repr(data)== 'PACIFIC \n  ARCTIC \n  ATLANTIC \n  '

首先,文件PASTED.txt的内容和文件PRIM.txt是一样的,因为我直接把PRIM.txt的内容复制粘贴到PASTED.txt中,没有经过Python字符串的处理。所以,当数据只是通过剪贴板从一个文件转移到另一个文件时,它并没有被修改。这证明了PRIM.txt的内容在剪贴板中是完整的,没有被破坏。

其次,通过剪贴板和raw_input()从文件转移到Python字符串的数据是被修改的;因此,修改发生在剪贴板和Python字符串之间。所以我想raw_input()在处理从剪贴板接收到的数据时,可能和Python解释器在读取文件数据时的处理方式是一样的。

接着,我进一步思考,为什么\r\n会被替换成\n,我认为这是因为“Windows格式”的数据变成了“Python格式”的数据,而剪贴板并没有对数据进行修改,因为它是由Windows操作系统控制的。

可惜的是,从屏幕复制的数据传给raw_input()时,并没有对换行符\r\n进行转换,尽管这些数据是通过Windows的剪贴板传递的,这让我之前的想法破灭了。

然后我想,Python之所以能识别数据的性质,不是因为数据的来源,而是因为数据中包含的信息;这种信息就是“格式”。我找到了一些关于Windows剪贴板的资料,确实有多种格式用于记录剪贴板中的信息:

http://msdn.microsoft.com/en-us/library/ms648709(v=vs.85).aspx

也许,Python对\r\n的修改解释和剪贴板中存在的这些格式有关,也可能没有关系。但我对这些内容还不够了解,不能确定。

有没有人能解释一下以上的观察结果?

.

.

谢谢你的回答,ncoghlan。但我觉得这不是原因:

  • sys.stdin没有mode这个属性

  • sys.stdin是指键盘,至少我理解是这样。然而,在我的代码中,数据并不是通过键盘输入的,而是通过剪贴板粘贴的。这是不同的。

关键是我不明白Python解释器是如何区分从剪贴板复制自文件的数据和从剪贴板复制自屏幕的数据的。

2

sys.stdin 是以文本模式打开的(你可以通过显示 sys.stdin.mode 来检查,看到它是 'r')。在Python中,如果你以文本模式打开任何文件,那么平台本身的换行符(在Windows上是 \r\n)会被转换成简单的换行符 \n,在Python字符串中显示。

你可以通过以 'r' 模式打开你的 PASTED.txt 文件,而不是 'rb',来看到这个过程是如何工作的。

撰写回答