【问题标题】:UTF-16 codepoint counting in pythonpython中的UTF-16代码点计数
【发布时间】:2016-09-01 20:13:49
【问题描述】:

我正在从我正在使用的 API(电报机器人)获取一些数据。 我正在使用与Telegram Bot api 交互的python-telegram-bot 库。 数据以 JSON 格式的 UTF-8 编码返回。 示例(sn-p):

{'message': {'text': '????\u200d????\u200d????\u200d????http://google.com/æøå', 'entities': [{'type': 'url', 'length': 21, 'offset': 11}], 'message_id': 2655}}

可以看出,'entities' 包含一个 url 类型的实体,它有一个长度和一个偏移量。 现在说我想在'text'属性中提取链接的url:

data = {'message': {'text': '????\u200d????\u200d????\u200d????http://google.com/æøå', 'entities': [{'type': 'url', 'length': 21, 'offset': 11}], 'message_id': 2655}}
entities = data['entities']
for entity in entities:
    start = entity['offset']
    end = start + entity['length']
    print('Url: ', text[start:end])

然而,上面的代码返回:'://google.com/æøå',这显然不是实际的 url。
原因是偏移量和长度在 UTF-16 代码点中。所以我的问题是:有没有办法在 python 中使用 UTF-16 代码点?我只需要能够数出它们就可以了。

我已经试过了:

text.encode('utf-8').decode('utf-16')

但这给出了错误:UnicodeDecodeError: 'utf-16-le' codec can't decode byte 0xa5 in position 48: truncated data

任何帮助将不胜感激。 我使用的是 python 3.5,但由于它是一个统一的库,让它在 python 2.x 中也能工作会很可爱。

【问题讨论】:

  • 欢迎来到本站!查看tour,了解更多有关提出问题的信息,这些问题将吸引高质量的答案。请edit your question 包含以下内容好吗? (1) 指向您正在使用的特定 API 的链接; (2) 您用于接收响应文本的代码; (3) 您用于获取entities 列表的代码?这些信息对我回答很有帮助。谢谢!
  • @cxw 我已经编辑了我的答案,以尽我所能反映变化。

标签: python python-3.x encoding utf-8 utf-16


【解决方案1】:

Python 已经将 UTF-8 编码的 JSON 数据正确解码为 Python (Unicode) 字符串,因此这里无需处理 UTF-8。

您必须编码为 UTF-16,获取编码数据的长度,然后除以 2。我将编码为 utf-16-leutf-16-be 以防止添加 BOM:

>>> len(text.encode('utf-16-le')) // 2
32

要使用实体偏移量,您可以编码为 UTF-16,在 加倍 偏移量上切片,然后再次解码:

text_utf16 = text.encode('utf-16-le')
for entity in entities:
    start = entity['offset']
    end = start + entity['length']
    entity_text = text_utf16[start * 2:end * 2].decode('utf-16-le')
    print('Url: ', entity_text)

【讨论】:

  • 当我尝试执行该代码时,我得到一个UnicodeDecodeError: 'utf-16-le' codec can't decode byte 0x6f in position 30: truncated data...这可能与python参考中的这个有关吗? “在 3.4 版中更改:utf-16* 和 utf-32* 编码器不再允许对代理代码点 (U+D800–U+DFFF) 进行编码。utf-32* 解码器不再解码对应的字节序列代理代码点。”
  • @bomjacob:不,这与那个无关。您设法将 UTF-16 字节对切成两半,检查您是否正确地将偏移量加倍。我在答案中发布的代码正确打印了http://google.com/æøå
  • @bomjacob:如果你有一个狭窄的 Python 版本(3.3 或更低版本),你首先不会遇到切片问题,因为 Python 字符串也会将非 BMP 字符视为具有宽度为 2。
  • @Martjin,好的,很高兴知道,因为我可能也必须将此代码移植到 python 2。有什么方法可以检查它是窄版还是宽版?
  • @bomjacob:检查sys.maxunicode的值;如果它设置为 65535 (== 0xffff),则您有一个窄版本,否则为宽版本(值将是 1114111 == 0x10ffff)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-10
  • 2021-06-15
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 2019-02-02
相关资源
最近更新 更多