假设你有两个 UTF-8 字符串
蟒蛇 3:
>>> s1
'è'
>>> s2
'è'
和红宝石:
> s1
=> "è"
> s2
=> "è"
虽然这些字符串看起来都一样,但它们不是:
>>> s1==s2
False
> s1==s2
=> false
这是因为虽然它是同一个字素,但它们实际上是两个不同的字节字符串:
>>> [[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", "̀"]]]
正如你所看到的,有多种方法可以组成一个字素,或者我们所说的字符。如果您有组合字符,例如'̀'
in s2
,则字符串的长度(以字节为单位)将与您预期的不同:
> s1.length==s2.length
=> false
在 Ruby 中,您可以使用\X
正则表达式扫描组成单个字素的字节或字节组:
> s2.scan(/\X/)
=> ["è"]
那么它们的逻辑长度将是相同的:
> s1.scan(/\X/).length==s2.scan(/\X/).length
=> true
或者,规范化字符串:
您还可以在 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
. (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