1

我正在将 Elasticsearch 与 Python 客户端一起使用,我对 unicode、ES、分析器和表情符号之间的交互有疑问。当我尝试通过 ES 分析器运行包含表情符号字符的 unicode 文本字符串时,它似乎搞砸了结果输出中的术语偏移量。

例如:

>> es.indices.analyze(body=u'\U0001f64f testing')
{u'tokens': [{u'end_offset': 10,
   u'position': 1,
   u'start_offset': 3,
   u'token': u'testing',
   u'type': u'<ALPHANUM>'}]}

这给了我术语测试的错误偏移量。

>> u'\U0001f64f testing'[3:10]
u'esting'

如果我用另一个 unicode 外来字符(例如日元符号)来做,我不会得到同样的错误。

>> es.indices.analyze(body=u'\u00A5 testing')
{u'tokens': [{u'end_offset': 9,
   u'position': 1,
   u'start_offset': 2,
   u'token': u'testing',
   u'type': u'<ALPHANUM>'}]}

>> u'\u00A5 testing'[2:9]
u'testing'

谁能解释发生了什么?

4

2 回答 2

1

我面临着完全相同的问题,并通过在以下代码中来回编码来正确映射偏移量UTF-16

TEXT = " carrot"
TOKENS = es.indices.analyze(body=TEXT)["tokens"]
# [
#   {
#     "token" : """""",
#     "start_offset" : 0,
#     "end_offset" : 2,
#     "type" : "<EMOJI>",
#     "position" : 0
#   },
#   {
#     "token" : "carrot",
#     "start_offset" : 3,
#     "end_offset" : 9,
#     "type" : "<ALPHANUM>",
#     "position" : 1
#   }
# ]

ENCODED_TEXT = text.encode("utf-16")
# b'\xff\xfe>\xd8U\xdd \x00c\x00a\x00r\x00r\x00o\x00t\x00'
BOM_MARK_OFFSET = 2

def get_decoded_token(encoded_text, token):
    start_offset = (token["start_offset"] * 2) + BOM_MARK_OFFSET
    end_offset = (token["end_offset"] * 2) + BOM_MARK_OFFSET
    return encoded_text[start_offset:end_offset].decode("utf-16")

assert get_decoded_token(ENCODED_TEXT, TOKENS[0]) == ""
assert get_decoded_token(ENCODED_TEXT, TOKENS[1]) == "carrot"

对于BOM_OFFSET_MARK,请参阅https://en.wikipedia.org/wiki/Byte_order_mark#UTF-16

于 2021-05-06T16:29:51.287 回答
0

Python 3.2 或更早版本?在 Windows 上的 Python 3.3 之前,有窄和宽的 Unicode 版本。窄版本每个字符使用两个字节,并使用 UTF-16 对 Unicode 代码点进行内部编码,这需要两个 UTF-16 代理来对高于 U+FFFF 的 Unicode 代码点进行编码。

Python 3.3.5 (v3.3.5:62cf4e77f785, Mar  9 2014, 10:35:05) [MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> len('\U0001f64f')
1
>>> '\U0001f64f'[0]
'\U0001f64f'

Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> len(u'\U0001f64f')
2
>>> u'\U0001f64f'[0]
u'\ud83d'
>>> u'\U0001f64f'[1]
u'\ude4f'

但是,在您的情况下,偏移量是正确的。因为 U+1F64F 使用两个 UTF-16 代理,“t”的偏移量是 3。我不确定你是如何得到你的输出的:

Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> x=u'\U0001f64f testing'
>>> x
u'\U0001f64f testing'
>>> x[3:10]
u'testing'
>>> y = u'\u00a5 testing'
>>> y[2:9]
u'testing'
于 2015-09-19T08:55:40.150 回答