当代码运行时,为什么在‘‘’前面打印‘’?

2024-09-24 00:23:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我试着写一个非常简单的输出语句,输出到一个csv文件中。它只是说明了数据的偏差范围,所以我使用了“±”符号,这样它将读取类似“5 ft/s^2±2.4%”的内容。在

我在Python3号工作。我尝试了三种不同的使用“±”符号的方法:ascii、unicode,以及直接将字符粘贴到编辑器中。见下文

val1 = 3.2
val2 = 2.4

s1 = val1 + "ft/sec^2 " + chr(241) + val2 + "%"
s2 = val1 + "ft/sec^2 " +  u'\u00B1' + val2 + "%"
s3 = val1 + "ft/sec^2 ±" + val2 + "%"

但是这三种方法的输出对我来说总是一样的。。。在

^{pr2}$

这个“问题”继续出现。我对编码之类的东西一点经验都没有。我搜索了一下,发现了一些似乎与我的情况有关的情况,但没有足够的理解来为我的具体情况拼凑出一个解决方案。在

我使用pandas DataFrame来收集数据,然后使用.to\u csv()方法创建csv。它的文档说明它默认为“utf-8”编码。在

这里有7行,它们重现了同样的问题。在

import pandas as pd 

df = pd.DataFrame(columns=['TestCol'])
df['TestCol'] = ["Test1: " + chr(241),
    "Test2: " + u'\u00B1',
    "Test3: " + "±"]
df.to_csv('TestExample.csv', index=False, encoding='utf-8')

在我的CSV中,我得到一个列,看起来像:

TestCol
Test1: ñ
Test2: ±
Test3: ±

感谢任何帮助、解释和知识!在


Tags: csv数据方法pandas编码df符号情况
3条回答

您正在向文件中写入UTF-8,但是无论您使用什么来查看它,都会将其视为拉丁语-1(或类似的Windows cp1252)。您可以尝试使用open对您正在写入的文件进行encoding='utf-8-sig'操作,这会将BOM放在文件的开头,这样应用程序就可以将其识别为UTF-8。或者你可以告诉你的查看器程序把它解释成UTF-8。我强烈建议而不是将其写成latin-1或类似的格式,因为这将使文本不可移植到具有其他语言环境的系统,而不必明确告诉人们如何解码它。在

s3包含一个UTF8编码值,其中±(U+00B1)的UTF8编码是\xc2\xb1。但是,您的终端将字节解释为ISO-8859编码的文本,而不是UTF-8编码的文本。在ISO-8859中,代码点C2是(您现在可能已经猜到了),而代码点B1是“±”。事实上,对于U+00A0和U+00BF之间的所有Unicode值,其UTF-8编码的第二个字节与它们的Unicode码位一致。此外,对于码位00-FF,ISO-8859-1与Unicode一致。在

Excel在打开.csv文件时采用Windows编码。这种编码取决于语言/国家,但在英语和西欧国家,它是^{},它非常类似于{a2}(也称为“拉丁语1”)。在

这种编码对每个字符使用一个字节。这意味着它最多允许256个不同的字符(事实上,它们少于256个,因为有些代码是为控制字符和不可打印字符保留的)。在

Python3使用Unicode来表示字符串。Unicode没有“只有256”符号的限制,因为它内部使用大约20位。实际上,Unicode可以表示世界上任何语言的任何字符(甚至是世界上一些语言的字符)。在

问题是,当Unicode必须写入文件(或通过网络传输)时,它必须作为字节序列进行“编码”。实现这一点的方法之一是“UTF-8”。在

UTF-8编码使用每个字符的可变字节数。它被设计为与ASCII兼容,因此ASCII表中的任何符号都用一个字节表示(这与它的ASCII代码一致)。但任何非ascii字符都需要超过1个字节来表示。特别是,字符±(codepointU+00B1或177)在用UTF-8编码时,需要两个字节的十六进制值c2和{}。在

当Excel读取这些字节时,由于它采用cp-1252编码,每个字符使用一个字节,所以它将序列c2b1解码为两个单独的字符。第一个被解码为Â,第二个被解码为±。在

Note Incidentally, unicode ñ (codepoint U+00F1, or 241) is encoded in UTF-8 also as two bytes, of values c3, b1, which when decoded as cp-1252 are shown as ñ. Note that the first one is now à instead of Â, but the second one is again (casually again) ±.

当写入解决方案1252时,应使用cp-2编码:

df.to_csv("file.csv", encoding="cp1252")

当然,这有一个潜在的问题。由于“cp-1252”最多只能表示256个符号,而Unicode可以表示超过1M个符号,因此可能会发生数据帧中的某些字符串数据使用“cp-1252”中无法表示的任何字符。在这种情况下,您将得到一个编码错误。在

另外,当用Pandas读回这个.csv时,必须指定编码,因为Pandas假定它是UTF-8。在

关于utf-8-sig的更新

其他答案和一些注释引用"utf-8-sig"编码,这将是另一个有效的(也许更可取)解决方案。我来详细说明一下这是什么。在

UTF8并不是将Unicode转换为字节序列的唯一方法,尽管它是一些标准中推荐的方法。另一个流行的选择是(曾经?)UTF-16。在这种编码中,所有Unicode字符都被编码为16位值(其中一些字符不能用这种方式表示,但是可以通过对某些字符使用两个16位值来扩展集合)。在

每个字符使用16位而不是8位的问题是,那么结束符是相关的。因为在网络内存中,16位或16位都是发送给磁盘的,实际上是在网络内存单元中写16位或不是。这些字节的发送顺序取决于体系结构。例如,假设您需要在磁盘中写入16位数字66ff(以十六进制表示)。你必须把它分成66和{},然后决定哪个先写。磁盘中的序列可以是66ff(这称为big-endian顺序),或者ff66(这称为小端顺序)。在

如果您在一个little-endian架构中,比如Intel,那么磁盘中字节的默认顺序将与big-endian架构中的不同。当然,问题是当您试图在一台架构与创建文件的机器不同的机器中读取文件时。您可能最终错误地将这些字节组合为ff66,w这将是一个不同的Unicode字符。在

因此,必须以某种方式在文件中包含有关创建时使用的endianity的信息。这就是所谓的BOM(字节顺序标记)的作用。它由Unicode字符FEFF组成。如果这个字符是作为文件中的第一个字符写入的,当文件被读回时,如果您的软件发现FEFF作为第一个字符,它将知道用于读取文件的endianity与写入文件时使用的相同。但是,如果它找到FFFE(顺序被交换),它将知道存在一个endianity不匹配,然后在读取时交换每对字节,以获得正确的Unicode字符。在

顺便说一句,Unicode标准的没有代码为FFFE的字符,以避免读取BOM时出现混淆。如果在开头找到FFFE,则表示结尾错误,必须交换字节。在

这些都与UTF-8无关,因为这种编码使用字节(而不是16位)作为信息的基本单位,因此它不受端接性问题的影响。但是,您可以用UTF-8编码FEFF(它将产生一个3字节的序列,值为EFBB,和BF),并将其作为文件中的第一个字符写入。当您指定utf-8-sig编码时,Python就是这样做的。在

在这种情况下,它的目的不是帮助确定endianity,而是充当一种“指纹”,帮助读回文件的软件猜测使用的编码是UTF-8。如果软件在文件的前3个字节中发现了“魔力值”EFBB、和{},那么它可以断定该文件存储在UTF-8中。这三个字节被丢弃,其余的从UTF-8解码。在

在微软的软件中,尤其是在微软的大多数软件中。显然,对于Excel来说,这也是有效的,因此,总结一下:

  • 您可以使用df.to_csv("file.csv", encoding="utf-8-sig")编写csv
  • Excel读取文件并在开始处找到EFBBBF。因此它丢弃这些字节,并假定文件的其余部分使用utf-8。在
  • 当稍后压缩c2b1出现在文件中时,它被正确地解码为UTF-8以产生±

这样做的好处是可以在任何Windows计算机上工作,不管它使用的是哪种代码页(cp1252适用于西欧,其他国家也可以使用其他代码页,但Unicode和UTF-8是通用的)。在

潜在的问题是如果您试图在非windows计算机中读取这个csv。第一个“魔法字节”EFBBBF对于读取它的软件来说是没有意义的。然后,可能会在文件的开头以“伪”字符结尾,这可能会导致问题。如果读取文件的软件采用UTF-8编码,这三个前字节将被解码为Unicode字符FFFE,但它们不会被丢弃。此字符是不可见的,宽度为零,因此无法使用任何编辑器“查看”它,但它仍将存在。如果读取文件的软件采用任何其他编码方式,例如“latin1”,那么前三个字节将被错误地解码为,并且它们将在文件的开头可见。在

如果使用python读回该文件,则必须再次指定utf-8-sig编码,以使python丢弃这三个初始字节。在

相关问题 更多 >