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

时间:2013-07-13 16:52:02

标签: python unicode utf-8 character-encoding

根据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应该代表单个角色。

2 个答案:

答案 0 :(得分:3)

不,声明是正确的。

在UTF-8 \xc3\xb1 假设代表单个字符。也就是说,如果您从UTF-8解码了字符串,那么您将得到一个字符,因此会有8个字符。

但是,在特定示例中,字符串被视为原始字符序列,而不是 UTF-8。因此,这两个八位字节会产生两个字符。

我可能会前进一点但是看到ipython的以下输出:

In [1]: b'Jalape\xc3\xb1o'
Out[1]: b'Jalape\xc3\xb1o'

In [2]: len(b'Jalape\xc3\xb1o')
Out[2]: 9

In [3]: b'Jalape\xc3\xb1o'.decode('utf8')
Out[3]: 'Jalapeño'

In [4]: len(b'Jalape\xc3\xb1o'.decode('utf8'))
Out[4]: 8

In [5]: 'Jalape\xf1o'
Out[5]: 'Jalapeño'

上面的代码适用于Python 3.对于Python 2,字节字符串(b'Jalape\xc3\xb1o')将替换为常规字符串('Jalape\xc3\xb1o'),常规字符串将替换为unicode字符串({{ 1}})。

答案 1 :(得分:1)

https://groups.google.com/forum/#!topic/comp.lang.python/1boxbYjhClg

Joshua Landau(回答我的问题写道)

  

“直接写入原始的UTF-8编码字符串,例如'Jalape \ xc3 \ xb1o',只生成一个9个字符的字符串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个字符吗?

不,Python往往对这些事情是正确的。

  

他说:\ xc3 \ xb1应该代表单个字符。然而,在与Pythonistas的一些互动之后,我更加困惑。

按照他说的方式,你会的。

  

参考上述段落:   1.“写一个原始的UTF-8编码字符串”是什么意思???

嗯,这并不像他给出的那样没有上下文。

  

在Python2中,曾经可以做'Jalape funny-n o'。这是一个'字节'字符串,其中每个字形在内部存储时长度为1个字节,因此每个字形根据字符集ASCII或Latin-1与整数相关联。如果这些字符集有一个搞笑的字形然后yay!别的,不!这里没有UTF-8 !!或UTF-16 !!这些是普通字节(8位)。

     

Unicode是字形和整数之间非常大的映射表,表示为Uxxxx或Uxxxx-xxxx。

等待我们的常驻unicode专家解释你实际上是错的原因

  

UTF-8 UTF-16是以高效方式存储这些大整数的编码。所以当DB说“编写一个原始的UTF-8编码字符串”时 - 这样做的唯一方法是使用Python3,其中默认的字符串文字存储在Unicode中,然后在内部使用UTF-8 UTF-16来存储各自结构中的字节数;或者,可以使用u'Jalape',这两种语言都是unicode(注意领先的'u')。

正确。

  
      
  1. 所以假设这是Python 3:'Jalape \ xYY \ xZZ o'(可读性的空间)DB所说的是,愚蠢的用户会期望Jalapeno有一个波浪形的n但是他得到的是:Jalape funny1 funny2 o(可读性空间)-9个字形或9个Unicode点或9个UTF8字符。正确的吗?
  2.   

我想是的。

  
      
  1. 这让我想知道他的意思是:   “这是因为在UTF-8中,多字节序列\ xc3 \ xb1应该代表单个字符U + 00F1,而不是两个字符U + 00C3和U + 00B1”
  2.   

他把一些事情搞混了,AFAICT。

  

有人可以花时间仔细阅读并澄清数据库的含义吗?

以下是一个简单的解释:你错了(或者你们两个几乎正确):

从Python 3开始:

>>> "\xc3\xb1"
'ñ'
>>> b"\xc3\xb1".decode()
'ñ'

“什么?”你尖叫,“那是错的!”但事实并非如此。让我解释一下。

Python 3的字符串要求你分别给每个字符( * winces 如果我错了* )。 Python将"\xc3"解释为"\N{LATIN CAPITAL LETTER A WITH TILDE}",将"\xb1"解释为"\N{PLUS-MINUS SIGN}"¹。 这意味着Python被赋予两个字符。 Python基本上就是 这样做:

number = int("c3", 16) # Convert from base16
chr(number) # Turn to the character from the Unicode mapping

当您提供Python 原始字节时,您说的就是这个 字符串在编码时看起来像 - 你没有给出Python Unicode, 但编码的Unicode 。这意味着当你解码它时(.decode()) 可以将多字节部分转换为相关字符。

要查看编码字符串与字符串本身的不同,请参阅:

>>> "Jalepeño".encode("ASCII", errors="xmlcharrefreplace")
b'Jalepeño'

那些代表同样的东西,但第一个(根据Python) 的东西,第二个需要解码

现在,将其恢复原状:

>>> "\xc3\xb1".encode()
b'\xc3\x83\xc2\xb1'

您可以看到编码的字节代表两个字符; 您在上面看到的字符串是而不是编码的字符串。编码是 Python内部

我希望有所帮助;祝你好运。

¹请注意,我发现"\N{...}"表格更容易阅读,并推荐它。