如何在Python中将代理对转换为普通字符串?

disbfnqx  于 2023-02-26  发布在  Python
关注(0)|答案(2)|浏览(195)

这是How can I convert JSON-encoded data that contains Unicode surrogate pairs to string?的后续问题。在那个问题中,OP有一个json.dumps()编码的文件,其中的表情符号表示为代理对-\ud83d\ude4f。他们在阅读文件和正确翻译表情符号时遇到了问题,正确的answer是文件中的每一行json.loads()json模块将处理从代理对到emoji(我假设是UTF8编码)的转换。
我的情况是这样的:假设我有一个普通的Python 3 unicode字符串,其中包含一个代理对:

emoji = "This is \ud83d\ude4f, an emoji."

我如何处理这个字符串来得到emoji的表示呢?我希望得到这样的结果:

"This is 🙏, an emoji."
# or
"This is \U0001f64f, an emoji."

我试过了

print(emoji)
print(emoji.encode("utf-8")) # also tried "ascii", "utf-16", and "utf-16-le"
json.loads(emoji) # and `.encode()` with various codecs

通常我会得到类似于UnicodeEncodeError: XXX codec can't encode character '\ud83d' in position 8: surrogates no allowed的错误。
我在Linux上运行Python 3.5.1,$LANG设置为en_US.UTF-8,我在命令行的Python解释器中运行了这些示例,在Sublime Text中运行的IPython中也运行了这些示例--看起来没有任何区别。

gcmastyq

gcmastyq1#

您在磁盘上的json文件中混合了一个文本字符串\ud83d(六个字符:\ u d 8 3 d)和一个 * 单个 * 字符u'\ud83d'(在Python源代码中使用字符串常量指定),这是Python 3中len(r'\ud83d') == 6len('\ud83d') == 1的区别。
如果你看到'\ud83d\ude4f' Python字符串(2个字符),那么上游有一个bug。通常,你不应该得到这样的字符串。如果你得到了一个字符串,并且你不能修复生成它的上游;您可以使用surrogatepass错误处理程序修复它:

>>> "\ud83d\ude4f".encode('utf-16', 'surrogatepass').decode('utf-16')
'🙏'

Python 2 was more permissive.
注意:即使您的json文件包含文字\ud83d\ude4f(12个字符);你不应该得到代理对

>>> print(ascii(json.loads(r'"\ud83d\ude4f"')))
'\U0001f64f'

注意:结果是1字符('\U0001f64f'),而不是代理项对('\ud83d\ude4f')。

qvtsj1bj

qvtsj1bj2#

由于这是一个重复出现的问题,并且错误消息稍微有些模糊,因此下面是更详细的说明。
代理是一种表示大于U+FFFF的Unicode码位的方法。
回想一下,Unicode最初被指定为包含65,536个字符,但很快就发现这不足以容纳世界上所有的字形。
作为UTF-16编码(否则为固定宽度)的扩展机制,设置保留区域以包含用于表示基本多语言平面之外的代码点的机制:这个特殊区域中的任何码位后面都必须跟有来自同一区域的另一个字符码,它们一起表示一个数字大于旧限制的码位。
(严格地说,代理人区被分成两半;一对中的第一个代理需要来自高代理的一半,第二个来自低代理。令人困惑的是,高代理U+D800-U+DBFF比低代理U+ DC 00-U+DFFF具有更低的码点数。)
这是专门支持UTF-16编码的遗留机制,不应用于其他编码;他们不需要,而且适用的标准明确规定这是不允许的。
换句话说,虽然U+12345可以用代理项对U+D808 U+ DF 45来表示,但除非特别使用UTF-16,否则应该直接表示它。
更详细地说,这是如何在UTF-8中表示为单个字符的:

0xF0 0x92 0x8D 0x85

下面是相应的替代序列:

0xED 0xA0 0x88
0xED 0xBD 0x85

正如已接受的答案中所建议的,您可以使用以下内容进行往返

>>> "\ud808\udf45".encode('utf-16', 'surrogatepass').decode('utf-16').encode('utf-8')
b'\xf0\x92\x8d\x85'

可能也请参见http://www.russellcottrell.com/greek/utilities/surrogatepaircalculator.htm

相关问题