Correctly extract Emojis from a Unicode string
我在python 2中工作,我有一个包含emoji和其他unicode字符的字符串。我需要将其转换为一个列表,其中列表中的每个条目都是一个字符/emoji。
1 2
| x = u'????xyz????'
char_list = [c for c in x] |
所需输出为:
1
| ['??', '??', 'x', 'y', 'z', '??', '??'] |
实际输出为:
1
| [u'\ud83d', u'\ude18', u'\ud83d', u'\ude18', u'x', u'y', u'z', u'\ud83d', u'\ude0a', u'\ud83d', u'\ude0a'] |
如何实现所需的输出?
- 我把它作为一个超集问题的复制品关闭了。把答案看清楚。如果它仍然不能解决您的问题,请编辑帖子以包括您的其他尝试。
- 我的问题不同于另一个问题,因为我处理的字符串中混合了emoji和非emoji字符。另外,我不想计算表情符号,而是想得到所有字符的列表。
- 清楚地说,你得到的清单是正确的。只是如果你打印一个list,它会显示repr的内容,而不是str的表单;你需要手动打印各个条目,才能看到str的表单(看起来像emoji)。例如,如果您执行print(u', '.join(char_list)),您将看到没有前导或尾随括号的预期结果。
- 字符串输入有7个字符,将emoji计数为单个字符。我得到的输出在列表中有11个条目。我需要得到一个输出列表,其中有7个条目对应于输入字符串中的字符。
- 它是哪个版本的python?在python 2中,x = '????xyz????'是非法的(或者可能被误解)。
- stackoverflow.com/questions/12907022/…的副本
- @伊万·波兹代夫,我不认为那个问题的答案能回答这个问题。
- @Ivan Pozdeev:它必须是python 2,因为实际输出使用u'...'字符串文本来表示值。它强调了这个问题缺少一个实际的最小、完整和可验证的例子。缺少from __future__ import unicode_literals或x字符串定义上的u前缀。
- @CPBurnz:它回答了OP的实际问题。一般来说,emoji可以跨越几个Unicode代码点(len(emoji) > 1任何python构建),例如?????(u+1f1eb u+1f1f7)。emoji在不同的上下文中是不同的。标题"从Unicode字符串中正确提取emojis"中的问题太复杂(太宽)。解决OP的问题并不能回答问题(正如目前接受的答案所示)。
- @亚伦:问题标题应该改变,以反映你接受的答案所涵盖的实际更窄的问题。否则,来自谷歌(Google)的访问者如果希望从标题中得到更广泛问题的答案,可能会失望。
首先,在python2中,需要使用unicode字符串(u'<...>')将unicode字符视为unicode字符。如果要使用字符本身而不是源代码中的\UXXXXXXXX表示形式,请更正源代码编码。
现在,根据python:当包含代理项对时获得正确的字符串长度,并且python返回单个unicode字符串的长度2,在python2"窄"构建(使用sys.maxunicode==65535时),32位unicode字符表示为代理项对,这对字符串函数是不透明的。这只在3.3(PEP0393)中被修复。
最简单的解决方案(除了迁移到3.3+之外)是从源代码编译一个python"wide"构建,如第3个链接所述。在它中,Unicode字符都是4字节(因此可能会占用内存),但是如果您需要常规处理宽的Unicode字符,这可能是一个可以接受的价格。
"窄"构建的解决方案是定制一组字符串函数(len,slice;可能是unicode的一个子类),用于检测代理对并将其作为单个字符处理。我找不到现有的(这很奇怪),但写起来并不难:
- 根据utf-16 u+10000至u+10ffff-维基百科,
- 第一个字符(高代理)在0xD800..0xDBFF范围内。
- 第二个字符(低代理)-在范围0xDC00..0xDFFF内
- 这些范围是保留的,因此不能作为常规字符出现
下面是检测代理项对的代码:
1 2 3 4 5 6 7 8 9 10 11 12
| 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 |
以及返回一个简单切片的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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] |
这里,您支付的价格是性能,因为这些功能比内置的慢得多:
1 2 3 4 5
| >>> 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 |
- 请注意,由于最近对emoji添加了许多花哨的内容,这一点稍微有点破损,因为有些emoji由多个代码点组成。示例包括标志("????"和etnical变体("????"vs "????")以及一些其他的东西,例如组合音调符号"a?"。
- @然后需要升级roeland is_surrogate,以检测这些内容,并返回附加单词数(=2字节字符),而不是真/假。前提是我们对这种情况很感兴趣(如果你问我的话,控制字符和音调符号是完全不同的事情),而其他类似标准化的工具不能完成这项任务。
- 我不认为标准化处理这些表情符号。严格正确的答案将迭代使用Unicode&174;标准附录29中的图形簇、冗长而晦涩的解释。但是如果没有一个可以处理这个问题的库,我可能会坚持迭代代码点。
- @Roeland:即使是\Xregex在一般情况下也没有帮助,例如,一些(聊天)软件显示:)(u+003a u+0029)为笑脸(图片),即在给定的上下文中是一个emoji。
- @是的。很久以前,我们打了一个冒号和一个括号。真正的老年人也会打破折号。但我认为操作询问的是Unicode的emoji字符。
- @Roeland:)在当前版本的iPhone Skype上工作。它显示为笑脸(图像)——这是emoji的字面定义:"电子通信中用来表达想法或情感的小数字图像或图标"。一般情况下,\X是不够的。这个问题的题目太宽泛了。
我将使用uniseg库(pip install uniseg:
1 2 3 4
| # -*- coding: utf-8 -*-
from uniseg import graphemecluster as gc
print list(gc.grapheme_clusters(u'????xyz????')) |
输出[u'\U0001f618', u'\U0001f618', u'x', u'y', u'z', u'\U0001f60a', u'\U0001f60a']和
1
| [x.encode('utf-8') for x in gc.grapheme_clusters(u'????xyz????'))] |
将以utf-8编码字符串的形式提供字符列表。
- 您的答案没有打印出所需的输出
- 好的,我将添加转换,以精确地提供问题所问的内容。
- @詹姆斯·霍普金,你能提供任何方法让我们把这些表情符号转换成类似Unicode的符号吗??在python 3中输入u'u0001f1618'
- 你可以写下:'??'.encode('unicode_escape')。尽管它产生字节,而不是字符串:b'\\U0001f618'。