python中的UTF-16代码点计数

jsm*_*bom 6 python encoding utf-8 utf-16 python-3.x

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

{'message': {'text': '\u200d\u200d\u200dhttp://google.com/æøå', 'entities': [{'type': 'url', 'length': 21, 'offset': 11}], 'message_id': 2655}}
Run Code Online (Sandbox Code Playgroud)

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

data = {'message': {'text': '\u200d\u200d\u200dhttp://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])
Run Code Online (Sandbox Code Playgroud)

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

我已经试过了:

text.encode('utf-8').decode('utf-16')
Run Code Online (Sandbox Code Playgroud)

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

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

Mar*_*ers 6

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
Run Code Online (Sandbox Code Playgroud)

要使用实体偏移量,您可以编码为 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)
Run Code Online (Sandbox Code Playgroud)

  • @bomjacob:检查 [`sys.maxunicode`](https://docs.python.org/2/library/sys.html#sys.maxunicode) 的值;如果它被设置为 65535 (== `0xffff`) 你有一个窄的构建,否则就是一个宽的构建(并且值将是 1114111 == `0x10ffff`)。 (2认同)