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

根据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
每个代码点也永远不会超过四个字节。

在返回'Response'(Python)中传递多个参数 - python

我在Angular工作,正在使用Http请求和响应。是否可以在“响应”中发送多个参数。角度文件:this.http.get("api/agent/applicationaware").subscribe((data:any)... python文件:def get(request): ... return Response(seriali…

Python exchangelib在子文件夹中读取邮件 - python

我想从Outlook邮箱的子文件夹中读取邮件。Inbox ├──myfolder 我可以使用account.inbox.all()阅读收件箱,但我想阅读myfolder中的邮件我尝试了此页面folder部分中的内容,但无法正确完成https://pypi.python.org/pypi/exchangelib/ 参考方案 您需要首先掌握Folder的myfo…

如何修复AttributeError:模块'numpy'没有属性'square' - python

Improve this question 我已经将numpy更新为1.14.0。我使用Windows10。我尝试运行我的代码,但出现此错误: AttributeError:模块“ numpy”没有属性“ square”这是我的进口商品:%matplotlib inline import matplotlib.pyplot as plt import ten…

R'relaimpo'软件包的Python端口 - python

我需要计算Lindeman-Merenda-Gold(LMG)分数,以进行回归分析。我发现R语言的relaimpo包下有该文件。不幸的是,我对R没有任何经验。我检查了互联网,但找不到。这个程序包有python端口吗?如果不存在,是否可以通过python使用该包? python参考方案 最近,我遇到了pingouin库。

AttributeError:'AnonymousUserMixin'对象没有属性'can' - python

烧瓶学习问题为了定制对匿名用户的要求,我在模型中设置了一个类: class MyAnonymousUser(AnonymousUserMixin): def can(self, permissions): return False def is_administrator(self): return False login_manager.anonymous…