gpt4 book ai didi

python - 运行代码时,为什么在'±'前面打印'Â'?

转载 作者:行者123 更新时间:2023-12-01 10:19:06 25 4
gpt4 key购买 nike

我正在尝试编写一个非常简单的输出语句,将其输出到一个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 + "%"

但是这三种方法的输出对我来说总是一样的...
3.2ft/sec^2 ±2.4%

这个“”继续出现。我完全没有编码方面的经验。我搜索了一些情况,这些情况似乎与我的情况有关,但了解不够,无法为我的具体情况找到解决方案。

我正在使用pandas DataFrame收集数据,然后使用.to_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: ±

任何帮助,解释和知识,我们感激不尽!

最佳答案

打开.csv文件时,Excel假定Windows编码。此编码取决于语言/国家/地区,但是在英语和西欧国家/地区中,它的名称是 cp-1252 ,与ISO-8859-1非常相似(也称为“latin1”)。
此编码每个字符使用一个字节。这意味着它最多允许256个不同的字符(实际上,它们少于256个,因为某些代码是为控制和不可打印的字符保留的)。
Python3使用Unicode表示字符串。 Unicode没有“仅256”个符号的限制,因为它在内部使用〜20位。实际上,Unicode可以代表世界上任何语言的任何字符(甚至包括世界之外的某些语言)。
问题在于,当必须将Unicode写入文件(或通过网络传输)时,必须将其“编码”为字节序列。实现此目的的方法之一,也是许多领域的当前标准,是“UTF-8”。
UTF-8编码每个字符使用可变数目的字节。它被设计为与ASCII兼容,因此ASCII表中的任何符号都用一个字节表示(与它的ascii码一致)。但是任何不在ascii中的字符都将需要超过1个字节来表示。特别是,字符±(编码点U+00B1或177)以UTF-8编码时,需要两个字节的十六进制值c2b1
当Excel读取这些字节时,由于它假定cp-1252编码(每个字符使用一个字节),因此它将序列c2b1解码为两个单独的字符。第一个解码为Â,第二个解码为±

注意顺便说一下,unicode ñ(代码点U+00F1或241)也以UTF-8编码为两个字节,值c3b1,当解码为cp-1252时显示为ñ。请注意,现在第一个是Ã而不是Â,但是第二个是(通常是再次)±

解决方案是向 Pandas 指示在写入文件时应使用cp-1252编码:

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位数字 66ff(以十六进制表示)。您必须将其“分解”为 66ff,并确定哪个首先写。磁盘中的序列可以是 66ff(称为大端顺序)或 ff66(称为小端顺序)。
如果您使用的是低端架构,例如Intel,则磁盘中字节的默认顺序将不同于大端架构。当然,问题是当您尝试在一台体系结构与创建该文件的体系结构不同的计算机上读取文件时。您可能最终将这些字节错误地汇编为 ff66,这将是另一个Unicode字符。
因此,必须以某种方式在文件中包含有关创建时使用的字节序的信息。这就是所谓的BOM(字节顺序标记)的作用。它由Unicode字符 FEFF组成。如果此角色是文件中的第一个字符,则在读回文件时,如果您的软件发现 FEFF作为第一个字符,它将知道用于读取文件的字节序与编写文件时使用的字节序相同。但是,如果找到 FFFE(交换了顺序),它将知道字节序不匹配,然后它将在读取时交换每对字节,以获取正确的Unicode字符。
顺便说一句,Unicode标准没有一个代码为 FFFE的字符,以避免在读取BOM时造成混淆。如果在开头找到 FFFE,则表示字节序错误,必须交换字节。
这些都不涉及UTF-8,因为此编码使用字节(而不是16位)作为信息的基本单位,因此可以避免字节顺序问题。不过,您可以使用UTF-8编码FEFF(这将导致3个字节的序列,其值分别为 EFBBBF)并将其作为文件中的第一个字符写入。当您指定 utf-8-sig编码时,这就是Python所做的。
在这种情况下,其目的不是帮助确定字节序,而是充当一种“指纹”,这可以帮助回读文件的软件猜测所使用的编码为UTF-8。如果软件发现“魔术值” EFBBBF作为文件中的前3个字节,则可以得出结论,该文件存储在UTF-8中。这三个字节被丢弃,其余的则从UTF-8解码。
特别是,Microsoft Windows在其大多数软件中都使用了此技术。显然,就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丢弃这三个初始字节。

    关于python - 运行代码时,为什么在'±'前面打印'Â'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57061645/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com