gpt4 book ai didi

python - UTF8编码的字符串'Jalape\xc3\xb1o'('Jalapeño')是否包含8或9个字符?

转载 作者:行者123 更新时间:2023-12-02 09:01:27 26 4
gpt4 key购买 nike

根据David Beazley的page 29 of Python Essential Reference (4th Edition)


直接编写原始UTF-8编码的字符串,例如'Jalape\xc3\xb1o'
只需生成一个九个字符的字符串U + 004A,U + 0061,U + 006C,
U + 0061,U + 0070,U + 0065,U + 00C3,U + 00B1,U + 006F,可能不是
您想要的。这是因为在UTF-8中,多字节序列
\xc3\xb1应该代表单个字符U + 00F1,而不是
两个字符U + 00C3和U + 00B1。


这不应该是8个字符-不是9个字符吗?他说:\xc3\xb1应该代表单个字符。

最佳答案

Steven D'Aprano的另一个superbly comprehensive answer from: comp.lang.python(我已尝试将其格式化为stackoverflow):


直接编写原始UTF-8编码的字符串,例如'Jalape\xc3\xb1o'
只需生成一个九个字符的字符串U + 004A,U + 0061,U + 006C,
U + 0061,U + 0070,U + 0065,U + 00C3,U + 00B1,U + 006F,可能不是
您想要的。这是因为在UTF-8中,多字节序列
\xc3\xb1应该代表单个字符U + 00F1,而不是
两个字符U + 00C3和U + 00B1。


这表明了基本概念的混乱,而仍然
不小心绊倒了基本事实吧。难怪是
迷惑了你,它也迷惑了我! :-)

编码不生成字符串,而是生成字节。所以
您所引用的人在谈论一个
“编码字符串”,他应该明确表示他的意思是
个字节,或者根本不提及字串。这些都可以工作:


UTF-8编码的字节字符串b'Jalape\xc3\xb1o'
UTF-8编码的字节b'Jalape\xc3\xb1o'


对于旧版Python(2.5或更旧版本),不幸的是b''
表示法不起作用,您必须省略b

如果Python不将ASCII字符与
个字节,并强迫您这样写字节字符串:


UTF-8编码的字节字符串b'\x4a\x61\x6c\x61\x70\x65\xc3\xb1\x6f'


从而使ASCII字符和字节之间的区别清晰可见。
但这会大大破坏向后兼容性,因此
Python继续将ASCII字符与字节混合在一起,即使在Python中也是如此。

重要的是字节b'Jalape\xc3\xb1o'
如上所示,九个十六进制值。其中七个代表
ASCII字符Jalapeo,其中两个不是ASCII。其
含义取决于您使用的编码。

(确切地说,其他七个字节的含义也取决于
编码。幸运的是,不幸的是,大多数情况下
并非所有编码对ASCII字符都使用与ASCII相同的十六进制值
本身就是这样,所以我将不再提及此事,而是假装
字符J始终等于十六进制字节4A。但是现在你知道了事实。)

由于我们使用的是UTF-8编码,因此两个字节\xc3\xb1表示
字符ñ,也称为LATIN SMALL LETTER N WITH TILDE。其他
编码,这两个字节将代表不同的内容。

因此,我认为原始人的意图是获取Unicode
文本字符串'Jalapeño'。如果他们在Unicode方面很明智,他们
可以写其中之一:


'Jalape\N{LATIN SMALL LETTER N WITH TILDE}o'
'Jalape\u00F1o'
'Jalape\U000000F1o'
'Jalape\xF1o' # hex
'Jalape\361o' # octal


而且要快乐。 (在Python 2中,他们需要在所有前缀前面加上
u,以使用Unicode字符串而不是字节字符串。)

但是可惜他们被那些散布神话的人误导了,
对Unicode的误解和误解
互联网,因此他们在某处查找ñ时发现它具有
UTF-8中的双字节十六进制值c3b1,并认为他们可以这样写:

'Jalape\xc3\xb1o'


这并没有按照他们的想法做。它创建一个文本字符串,
Unicode字符串,带有9个字符:

J a l a p e à ± o


为什么?由于字符 Ã的序数值为195(十六进制的 c3),因此
\xc3是字符 Ã;同样, \xb1是字符 ±,具有
序号177(十六进制的 b1)。因此,他们发现了邪恶
mojibake

相反,如果它们以字节串开头并显式解码
作为UTF-8,他们会没事的:

# I manually encoded 'Jalapeño' to get the bytes below:
bytes = b'Jalape\xc3\xb1o'
print(bytes.decode('utf-8'))



我最初的问题是:这不应该是8个字符-不是9个字符吗?他
说: \xc3\xb1应该代表单个字符。然而
与其他Pythonista使用者互动后,我感到更加困惑。


取决于上下文。 \xc3\xb1可能表示Unicode字符串
'\xc3\xb1'(在Python 2中,写为 u'\xc3\xb1'),或者可能表示字节-
字符串 b'\xc3\xb1'(在Python 2.5或更早版本中,不包含 b编写)。

作为一个字符串, \xc3\xb1表示两个字符,其序号为 0xC3(或
十进制195)和 0xB1(或十进制177),即 'Ã''±'

作为字节, \xc3\xb1代表两个字节(嗯,嗯),这可能意味着
几乎任何东西:


16位Big Endian整数50097
16位Little Endian整数45507
4x4黑白位图
Big5编码字节中的字符 '簽'(CJK UNIFIED IDEOGRAPH-7C3D)
'뇃'(HANGUL SYLLABLE NWAES)以UTF-16(Big Endian)编码的字节
'ñ'以UTF-8编码的字节
Latin-1编码字节中的两个字符 'ñ'
Macroman编码字节中的 '√±'
ISO-8859-7编码字节中的 'Γ±'


等等。不知道上下文,就无法告诉
这两个字节代表什么,或者是否需要将它们合在一起
作为一对,或作为两个不同的事物。


参考以上段落:
他“写原始的UTF-8编码的字符串”是什么意思?


他表示自己很困惑。您不会通过编码获得文本字符串,而是
个字节(我将接受“字节字符串”)。形容词“原始”不是真的
在这种情况下意味着任何东西。您有已编码的字节,或者
有一个包含字符的字符串。 Raw并没有真正的意义
除了“嘿,注意,这是低级的东西”(对于某些定义
“低级别”)。


在Python2中,一次可以执行“ Jalape funny-n o”。


对于讲西班牙语的人来说,这没什么好笑的。

就个人而言,我一直认为“ o”很有趣。说“女人”
和“女人”大声-在第一个中,听起来像“ w-oo-man”
第二听起来像是“ w-i-men”。现在好笑。但是我离题了。

如果您在Python 2中输入 'Jalapeño'(带或不带 b前缀),则
您得到的结果将取决于您的终端设置,但是机会是
高,终端将在内部将字符串表示为UTF-8,
这给你字节

b'Jalape\xc3\xb1o'


这是九个字节。打印后,您的终端将尝试打印每个
单独字节,给出:


字节 \x4a打印为 J
字节 \x61打印为 a
字节 \x6c打印为 l
...


等等。如果您不走运,您的终端甚至可能足够聪明
将两个字节 \xc3\xb1打印为一个字符,为您提供 ñ
希望的。为什么倒霉?因为你得到了正确的结果
事故。下次您在不同的终端上执行相同的操作时,或者
将同一终端设置为不同的编码,您将获得一个完全
结果不同,并认为Unicode太混乱而无法使用。

使用Python 2.5,我在这里连续打印了三次相同的字符串,
每次更改终端的编码:

py> print 'Jalape\xc3\xb1o'  # terminal set to UTF-8
Jalapeño
py> print 'Jalape\xc3\xb1o' # and ISO-8859-6 (Arabic)
Jalapeأ�o
py> print 'Jalape\xc3\xb1o' # and ISO-8859-5 (Cyrillic)
JalapeУБo


哪个是“正确的”?答:没有。甚至没有第一个
意外刚好是我们所希望的。

真的,不要为自己感到困惑而感到难过。在Python 2和
终端真的很难做正确的事,很容易得到
感到困惑,因为某些正确的事情有时会发生
不。


这是一个“字节”字符串,其中每个字形的长度为1个字节


不。这是一个字符串。字形不进入其中。字形是
您在屏幕上看到或打印在上面的字母的小图片
纸。它们可以是位图或精美的矢量图形。他们不太可能
每个字节一个字节-每个字形更可能是200个字节,
粗略的计算1,但取决于它是否是位图,
Postscript字体,OpenType字体或其他。


当内部存储时,每个字形都是
与每个字符集ASCII或Latin-1的整数相关联。如果这些
字符集有一个有趣的N字形,然后!否则不!没有UTF-8
这里!!或UTF-16!这些是纯字节(8位)。


你越来越近了。但是你是对的:Python 2的“字符串”是字节-
字符串,这意味着没有UTF-8。但是您的终端可能
将这些字节视为UTF-8,因此不小心执行了“对”(错误)
事情。


Unicode是字形和整数之间的一个很大的映射表,


不是字形。在抽象的“字符”和整数之间,称为Code
点。 Unicode包含:


不同的字母,数字,字符
重音字母
自己的口音
符号,表情
连字的字符和变体形式
仅与旧编码向后兼容才需要的chars
空格
控制字符
保留供私人使用的代码点,这可能意味着您喜欢的任何内容
保留为“永不使用”的代码点
明确标记为“不是字符”的代码点


可能还有我忘记的其他人。


表示为 UxxxxUxxxx-xxxx


正式的Unicode表示法是:

U+xxxx
U+xxxxx
U+xxxxxx


U+,后面紧跟四个,五个或六个十六进制数字。 U
总是大写。不幸的是,Python不支持该表示法,并且
您必须使用四个或八个十六进制数字,例如:

\uFFFF
\U0010FFFF


对于不超过255的代码点(标准),您也可以使用十六进制或八进制
逃脱,例如 \xFF \3FF


UTF-8 UTF-16是要存储的编码
那些大整数以一种有效的方式。


几乎正确。它们不一定有效。

Unicode代码点只是抽象数字,我们赋予了一些含义
至。代码点65( U+0041,因为十六进制41 ==十进制65)表示字母 A
等等。想象一下这些抽象的代码点浮在脑海中。
您如何将代码点的抽象概念转化为具体形式
一台电脑?一切都以相同的方式放入计算机:以字节为单位,因此
我们必须将每个抽象代码点(一个数字)变成一系列
个字节。

Unicode代码点的范围从 U+0000U+10FFFF,这意味着我们可以
只需使用三个字节,它们的取值范围为000000至10FFFF
十六进制。超出此范围的值(例如110000)将是错误。
为了提高效率,最好使用四个字节,
即使这四个之一始终具有零值。

简而言之,就是UTF-32编码:任何字符都完全使用
四个字节。例如。代码点 U+0041(字符 A)是十六进制字节 00000041
或可能的 41000000,具体取决于您的计算机是Big Endian还是
小端。

由于大多数文本使用的序数值都非常低,因此非常浪费
的记忆。因此,UTF-16每个字符仅使用两个字节,而且很奇怪
使用所谓的“代理对”来解决所有不合适的方案
分成两个字节。对于“作品”的某些定义,它可以工作,但是
复杂,如果需要代码点,您真的想避免使用UTF-16
高于 U+FFFF

UTF-8使用整洁的变量编码,其中低序字符
值被编码为单个字节(更好的是:它与
ASCII使用,这意味着可以假定世界上所有内容的旧软件
是ASCII将会继续有效,而且大多数情况下都可以正常工作)。高阶人得到
编码为两个,三个或四个字节2。最好的是,不同于大多数
历史上可变宽度编码,UTF-8是自同步的。在
旧式编码,如果单个字节损坏,它可能会损坏
从那时起的一切。使用UTF-8,单个损坏的字节将
仅破坏包含它的单个代码点,之后的所有内容
会没事的。


因此,当数据库说“写一个
原始的UTF-8编码字符串”-唯一的方法就是使用
Python3中的默认字符串文字存储在Unicode中,
然后将在内部使用UTF-8 UTF-16将字节存储在
各自的结构;或者,可以使用 u'Jalape'这是unicode
两种语言(注意前导 u)。


Python从不内部使用UTF-8将字符串存储在内存中。因为
这是一种可变宽度编码,如果
他们使用UTF-8进行存储。

相反,Python使用三种不同系统之一:


在Python 3.3之前,您可以选择。编译Python时
解释器,您可以选择在输入中使用UTF-16还是UTF-32
内存存储。此选择称为“窄”或“宽”构建。一个箭头
构建使用较少的内存,但无法处理 U+FFFF以上的代码点
好。广泛的构建使用更多的内存,但可以处理
代码点完美。
从Python 3.3开始,如何在内存中存储字符串的选择
在构建Python解释器时不再预先决定。
相反,Python会自动选择最有效的内部
每个字符串的表示形式。仅使用ASCII的字符串
或Latin-1字符每个字符使用一个字节;使用代码的字符串
最多 U+FFFF的点每个字符使用两个字节;而且只有字符串
使用上面的代码点,每个字符使用四个字节。



因此,假设这是Python 3: 'Jalape \xYY \xZZ o'(空格
可读性)DB的意思是,愚蠢的用户会期望
墨西哥胡椒的波浪形N,但他得到的却是:贾拉普funny1 funny2
o(可读性空间)-9个字形或9个Unicode点或9-UTF8
字符。正确?


有点儿。往上看。


这让我想知道他的意思:“这是因为
UTF-8,多字节序列 \xc3\xb1应该表示
单个字符 U+00F1,而不是两个字符 U+00C3U+00B1


他表示单个代码点 U+00F1(字符 ñ,带波浪号的n)
如果使用进行编码,则存储为两个字节 c3b1(以十六进制表示)
UTF-8。但是如果您将字符 \xc3 \xb1填充到Unicode字符串中
(而不是字节),那么您将获得两个Unicode字符 U+00C3U+00B1

换句话说,在字符串中,Python处理十六进制转义 \xC3
作为编写Unicode代码点 \u00C3的另一种方式,或者
\U000000C3

但是,如果您创建一个字节字符串:

b'Jalape\xc3\xb1o'


通过查找UTF-8编码表(大概是原始的)
发布者做了,然后将这些字节解码为字符串,您将得到
你期望的。使用Python 2.5,不需要 b前缀:

py> tasty = 'Jalape\xc3\xb1o'  # actually bytes
py> tasty.decode('utf-8')
u'Jalape\xf1o'
py> print tasty.decode('utf-8') # oops I forgot to reset my terminal
JalapeУБo
py> print tasty.decode('utf-8') # terminal now set to UTF-8
Jalapeño




1假定字体文件的大小为100K,并且它的字形为256
字符。每个字形可计算为195个字节。

2从技术上讲,UTF-8方案可以处理31位代码点,最高可达
(假设的)代码点U + 7FFFFFFF,每个代码最多使用六个字节
点。但是Unicode永远不会超过U + 10FFFF,所以UTF-8
每个代码点也永远不会超过四个字节。

关于python - UTF8编码的字符串'Jalape\xc3\xb1o'('Jalapeño')是否包含8或9个字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17632246/

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