从Unicode字符串中正确提取表情符号

问题描述

首先,在Python2中,您需要使用Unicode字符串(u'<...>')将Unicode字符视为Unicode字符。而且正确的源编码,如果你想使用的字符本身,而不是\UXXXXXXXX在源代码表示。

现在,按照Python:在包含代理对时获取正确的字符串长度,并且Python为单个Unicode字符串返回2的长度,在Python2“ narrow”构建中(带有sys.maxunicode==65535),将32位Unicode字符表示为代理对,对字符串函数不是透明的。仅在3.3(PEP0393)中已解决此问题。

在其中,Unicode字符全为4字节(因此是潜在的内存消耗),但是如果您需要例行处理宽的Unicode字符,这可能是可以接受的价格。

是 (lenslice;可能作为的子类unicode),该 将检测代理对并将其作为单个字符处理。我无法轻易找到一个现有的(这很奇怪),但是写起来并不难:

因此,这是检测代理对的代码

def is_surrogate(s,i):
    if 0xD800 <= ord(s[i]) <= 0xDBFF:
        try:
            l = s[i+1]
        except IndexError:
            return False
        if 0xDC00 <= ord(l) <= 0xDFFF:
            return True
        else:
            raise ValueError("Illegal UTF-16 sequence: %r" % s[i:i+2])
    else:
        return False

还有一个返回简单切片的函数

def slice(s,start,end):
    l=len(s)
    i=0
    while i<start and i<l:
        if is_surrogate(s,i):
            start+=1
            end+=1
            i+=1
        i+=1
    while i<end and i<l:
        if is_surrogate(s,i):
            end+=1
            i+=1
        i+=1
    return s[start:end]

在这里,您付出的代价是性能,因为这些功能比内置功能要慢得多:

>>> ux=u"a"*5000+u"\U00100000"*30000+u"b"*50000
>>> timeit.timeit('slice(ux,10000,100000)','from __main__ import slice,ux',number=1000)
46.44128203392029    #msec
>>> timeit.timeit('ux[10000:100000]','from __main__ import slice,ux',number=1000000)
8.814016103744507    #usec

解决方法

我在Python 2中工作,我有一个包含表情符号和其他unicode字符的字符串。我需要将其转换为列表,其中列表中的每个条目都是单个字符/表情符号。

x = u'