gpt4 book ai didi

python-2.7 - 如何在 Python 中解释 Unicode 符号?

转载 作者:行者123 更新时间:2023-12-02 17:06:26 25 4
gpt4 key购买 nike

如何将像 'U+1F600' 这样的正式 Unicode 符号转换成这样的东西:'\U0001F600',我在网站上看到它表示为“Python Src”在线?

我的最终目标是在 Python(2.x) 中将 Unicode 用于表情符号,我能够通过这种方式实现它:

unicode_string = '\U0001F600'
unicode_string.decode('unicode-escape')

如果您能指出上述问题涉及的不同字符集,我将不胜感激。

最佳答案

最简单的方法是将符号视为字符串:

>>> s = 'U+1F600'
>>> s[2:] # chop off the U+
'1F600'
>>> s[2:].rjust(8, '0') # pad it to 8 characters with 0s
'0001F600'
>>> r'\U' + s[2:].rjust(8, '0') # prepend the `\U`
'\\U0001F600'

将字符串解析为十六进制然后格式化结果数字可能会更清晰一些:

>>> int(s[2:], 16)
128512
>>> n = int(s[2:], 16)
>>> rf'\U{n:08X}'
'\\U0001F600'

……但我不确定这样理解是否真的更容易。


如果您需要从较大的字符串中提取这些,您可能需要一个正则表达式。

我们想要匹配一个文字 U+ 后跟 1 到 8 个十六进制数字,对吗?所以,那是 U\+[0-9a-fA-F]{1,8} .除了我们真的不需要包含 U+ 只是为了用 [2:] 实现它,所以让我们将其余部分分组:U\+([0-9a-fA-F]{1,8}) .

>>> s = 'Hello U+1F600 world'
>>> re.search(r'U\+([0-9a-fA-F]{1,8})', s)
<_sre.SRE_Match object; span=(6, 13), match='U+1F600'>
>>> re.search(r'U\+([0-9a-fA-F]{1,8})', s).group(1)
'1F600'

现在,我们可以使用 re.sub 和一个函数来应用 \U 前缀和 rjust 填充:

>>> re.sub(r'U\+([0-9a-fA-F]{1,8})', lambda match: r'\U' + match.group(1).rjust(8, '0'), s)
'Hello \\U0001F600 world'

如果您将函数定义为外线,这可能更具可读性:

>>> def padunimatch(match):
... return r'\U' + match.group(1).rjust(8, '0')
>>> re.sub(r'U\+([0-9a-fA-F]{1,8})', padunimatch, s)
'Hello \\U0001F600 world'

或者,如果您更喜欢用数字来表示:

>>> def padunimatch(match):
... n = int(match.group(1), 16)
... return rf'\U{n:08X}'
>>> re.sub(r'U\+([0-9a-fA-F]{1,8})', padunimatch, s)
'Hello \\U0001F600 world'

当然,您已经知道如何完成最后一部分,因为这是您的问题,对吧?好吧,不完全是:您不能对字符串调用 decode,只能对 bytes 调用。解决此问题的最简单方法是直接使用编解码器:

>>> x = 'Hello \\U0001F600 world'
>>> codecs.decode(x, 'unicode_escape')
'Hello 😀 world'

…除非你使用的是 Python 2。在那种情况下,str 类型不是 Unicode 字符串,它是一个字节串,所以 decode 实际上有效美好的。但是在 Python 2 中,您会遇到其他问题,除非您的所有文本都是纯 ASCII(任何非 ASCII 字符编码为 U+xxxx 序列)。

例如,假设您的输入是:

>>> s = 'Hej U+1F600 världen'

在 Python 3 中,这很好。 s 是一个 Unicode 字符串。在幕后,我的控制台正在将 Python UTF-8 编码字节发送到标准输入,并期望从标准输出返回 UTF-8 编码字节,但这就像变魔术一样有效。 (嗯,不是很神奇——你可以 print(sys.stdin.encoding, sys.stdout.encoding) 看看 Python 知道我的控制台是 UTF-8 并使用它来解码和编码我的代表。)

在 Python 2 中,它不是。如果我的控制台是 UTF-8,我实际所做的相当于:

>>> s = 'Hej U+1F600 v\xc3\xa4rlden'

... 如果我尝试将其解码为 unicode-escape,Python 2 会将那些 \xc3\xa4 字节视为拉丁语-1 字节,而不是 UTF-8:

>>> s = 'Hej \U0001F600 v\xc3\xa4rlden'

...所以你最终得到的是:

>>> s.decode('unicode_escape')
u'Hej \U0001f600 v\xc3\xa4rlden'
>>> print(s.decode('unicode_escape'))
Hej 😀 världen

但是,如果您尝试先将其解码为 UTF-8,然后将那个解码为 un​​icode_escape,会怎样?

>>> s.decode('utf-8')
u'Hej \\U0001F600 v\xe4rlden'
>>> print(s.decode('utf-8'))
Hej \U0001F600 världen
>>> s.decode('utf-8').decode('unicode-escape')
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 16: ordinal not in range(128)

Python 3 不允许您在 Unicode 字符串上调用 decode,Python 2 允许您这样做——但它通过尝试 encode 来处理它首先转换为 ASCII,所以它有一些东西要解码,显然这里失败了。

而且您不能像在 Python 3 中那样直接使用编解码器:

>>> codecs.decode(s.decode('utf-8'), 'unicode_escape')
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 16: ordinal not in range(128)

您可以解码 UTF-8,然后对结果进行 unicode 转义,然后对所有内容进行 un-unicode 转义,但即使这样也不太正确:

>>> print(s.decode('utf-8').encode('unicode_escape').decode('unicode_escape'))
Hej \U0001F600 världen

为什么?因为 unicode-escape 在修复我们现有的 Unicode 字符的同时,也转义了我们的反斜杠!

如果您知道在原始源代码中肯定没有您不想解析的 \U 转义符,那么有一个快速解决方法:只需替换转义符反斜杠:

>>> print(s.decode('utf-8').encode('unicode_escape').replace(r'\\U', r'\U').decode('unicode_escape'))
Hej 😀 världen

如果这一切看起来像一个巨大的痛苦......好吧,是的,这就是 Python 3 存在的原因,因为在 Python 2 中正确处理 Unicode(注意我什至没有真正处理它正确地……)是一个巨大的痛苦。

关于python-2.7 - 如何在 Python 中解释 Unicode 符号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51585291/

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