python和ruby中的不同编码

时间:2017-07-17 15:19:11

标签: python ruby encoding ord

我试图在Python中模仿Rubys .bytesize字符串函数。但是我遇到某些字符的问题,例如"“"

在Ruby中

"‘".bytesize returns 3
"‘".bytes returns [226, 128, 152]

在Python中

ord("‘") returns 8216
len(ord("‘")) returns 1

两种语言之间的编码有何不同?这进一步与不同的在线转换器混淆,提供类似的对比结果。例如 - http://www.unit-conversion.info/texttools/ascii/产生与Ruby相同的结果,而https://www.branah.com/ascii-converter产生与Python相同的结果。

2 个答案:

答案 0 :(得分:1)

您正在处理UTF-8字符串,忘记字节。

String#codepoints将返回代码点数组,String#length返回UTF-8字符串的长度:

"‘".codepoints #⇒ [8216]
"‘".length     #⇒ 1

String#unpack提供对字形表的低级访问。

"‘".unpack "U+"

您是否仍希望获得对字节的访问权限,您可以:

"‘".unpack "C*"
#⇒ [226, 128, 152]

要在python中获取UTF-8符号的字节,可以使用bytes

>>> chars = bytes("‘".encode("utf8"))
>>> chars
#⇒ b'\xe2\x80\x98'
>>> len(chars)
#⇒ 3

答案 1 :(得分:0)

假设您在

中有两个UTF-8字符串

Python 3:

>>> s1
'è'
>>> s2
'è'

和Ruby:

> s1
=> "è"
> s2
=> "è"

虽然这些字符串的所有看起来都是,但它们不是:

>>> s1==s2
False

> s1==s2
=> false

这是因为虽然它是相同的grapheme,但它们实际上是两个不同的字节串:

>>> [[s, len(s), list(s)] for s in (s1,s2)]
[['è', 1, ['è']], ['è', 2, ['e', '̀']]]
> [s1,s2].map {|s| [s, s.length, s.each_char.to_a]}
=> [["è", 1, ["è"]], ["è", 2, ["e", "̀"]]] 

正如您所看到的,有多种方法可以构成单个字形,或者我们称之为字符的方式。如果您有'̀'中的s2等撰写字符,则字符串的长度(以字节为单位)将与您预期的不同:

> s1.length==s2.length
=> false

在Ruby中,您可以使用\X正则表达式扫描构成单个字素的字节或字节组:

> s2.scan(/\X/)
=> ["è"]

然后他们的逻辑长度将是相同的:

> s1.scan(/\X/).length==s2.scan(/\X/).length
=> true

或者,规范化字符串:

您还可以normalize Ruby中的s2字符串将两个字节合并为一个等效的字形:

> s2.unicode_normalize.length==s1.length
=> true

在Python中,您可以使用unicodedate进行规范化:

>>> import unicodedata
>>> unicodedata.normalize('NFC', s2) == s1
True
>>> len(unicodedata.normalize('NFC', s2)) == len(s1)
True

或者安装并使用支持\X的{​​{3}}。 (re模块不支持\X

如果您真的想要在Python中使用与Ruby相同的逐字节方法,那么您可以这样做:

>>> [int(e) for e in bytes("‘".encode('utf-8'))]
[226, 128, 152]
> "‘".bytes
=> [226, 128, 152]

但我不确定你打算怎么做......

或者,如果您想要相同的ord值:

>>> ord("‘")
8216
> "‘".ord
=> 8216