如何使用python在字符串中查找和计算表情符号?
Posted
技术标签:
【中文标题】如何使用python在字符串中查找和计算表情符号?【英文标题】:How to find and count emoticons in a string using python? 【发布时间】:2013-10-09 13:27:36 【问题描述】:此主题已在 link1、link2、link3 解决了基于文本的表情符号。但是,我想做一些与匹配简单表情符号略有不同的事情。我正在整理包含表情符号图标的推文。以下 unicode 信息仅包含此类表情符号:pdf。
使用包含来自pdf 的任何这些表情符号的英文单词字符串,我希望能够将表情符号的数量与单词的数量进行比较。
我前进的方向似乎不是最佳选择,我正在寻求帮助。正如您在下面的脚本中看到的,我只是打算从命令行完成这项工作:
$cat <file containing the strings with emoticons> | ./emo.py
emo.py 伪脚本:
import re
import sys
for row in sys.stdin:
print row.decode('utf-8').encode("ascii","replace")
#insert regex to find the emoticons
if match:
#do some counting using .split(" ")
#print the counting
我遇到的问题是解码/编码。我还没有找到如何编码/解码字符串的好选择,所以我可以正确找到图标。我要搜索的字符串的一个例子是找到单词和表情符号的数量如下:
“笑脸表情摇滚!我喜欢你。”
挑战:你能写一个脚本来计算这个字符串中的单词和表情符号的数量吗?请注意,表情符号都位于单词旁边,中间没有空格。
【问题讨论】:
这里是否需要使用正则表达式? 这些都是非常基本的正则表达式内容,所以……你读过Regular Expression HOWTO,或者更好的是第三方教程吗? 【参考方案1】:首先,这里根本不需要编码。你有一个 Unicode 字符串,re
引擎可以处理 Unicode,所以就用它吧。
character class 可以包含一系列字符,方法是指定第一个和最后一个并在其间加上连字符。您可以使用\U
转义序列指定您不知道如何输入的Unicode 字符。所以:
import re
s=u"Smiley emoticon rocks!\U0001f600 I like you.\U0001f601"
count = len(re.findall(ru'[\U0001f600-\U0001f650]', s))
或者,如果字符串足够大,构建整个 findall
列表似乎很浪费:
emoticons = re.finditer(ru'[\U0001f600-\U0001f650]', s)
count = sum(1 for _ in emoticons)
算字,可以分开做:
wordcount = len(s.split())
如果您想一次完成所有操作,可以使用交替组:
word_and_emoticon_count = len(re.findall(ru'\w+|[\U0001f600-\U0001f650]', s))
正如@strangefeatures 所指出的,3.3 之前的 Python 版本允许“窄 Unicode”构建。而且,例如,大多数 CPython Windows 版本都很窄。在窄版本中,字符只能在U+0000
到U+FFFF
范围内。没有办法搜索这些字符,但没关系,因为它们不存在可搜索;如果您在编译正则表达式时遇到“无效范围”错误,您可以假设它们不存在。
当然,除了很有可能无论您从何处获取实际字符串,它们都是 UTF-16-BE 或 UTF-16-LE,所以字符确实存在,它们只是被编码成代理对。你想匹配那些代理对,对吧?因此,您需要将您的搜索转换为代理对搜索。也就是说,将您的高代码点和低代码点转换为代理对代码单元,然后(用 Python 术语)搜索:
(lead == low_lead and lead != high_lead and low_trail <= trail <= DFFF or
lead == high_lead and lead != low_lead and DC00 <= trail <= high_trail or
low_lead < lead < high_lead and DC00 <= trail <= DFFF)
如果您不担心接受伪造的 UTF-16,则可以省略最后一种情况中的第二个条件。
如果不清楚如何将其转换为正则表达式,这里是 UTF-16-BE 中的范围 [\U0001e050-\U0001fbbf]
的示例:
(\ud838[\udc50-\udfff])|([\ud839-\ud83d].)|(\ud83e[\udc00-\udfbf])
当然,如果您的范围足够小,low_lead == high_lead
这会变得更简单。例如,可以使用以下命令搜索原始问题的范围:
\ud83d[\ude00-\ude50]
最后一个技巧,如果您实际上不知道您将获得 UTF-16-LE 还是 UTF-16-BE(并且 BOM 远离您正在搜索的数据):因为没有代理前导或尾随代码单元作为独立字符或一对的另一端有效,您可以双向搜索:
(\ud838[\udc50-\udfff])|([\ud839-\ud83d][\udc00-\udfff])|(\ud83e[\udc00-\udfbf])|
([\udc50-\udfff]\ud838)|([\udc00-\udfff][\ud839-\ud83d])|([\udc00-\udfbf]\ud83e)
【讨论】:
我不得不将你的 r' 更改为 u' 为 re.findall(u'[\U0001f600-\U0001f650]', s.decode('utf-8')),然后正确找到表情符号。谢谢@abarnert! @simplyclimb:是的,你需要u'…'
——而且s
变量也应该是一个unicode字符串。 (出于某种原因,我假设您使用的是 Python 3,但看看您的问题,显然是 2.x。)但是您仍然想要 r
。在这种情况下,删除它并不重要,因为 Python Stirng 文字将解释转义序列 \U0001f600
与 re
引擎完全相同的方式......但始终使用原始字符串作为正则表达式是一个好主意,除非你有特定的理由不这样做,而不是研究每个正则表达式来确定您是否需要原始字符串。
re ur'[\U0001f600-\U0001f650]'
无法在低于 3.3 的某些 Python 版本上编译(我认为窄版本 - 即 sys.maxunicode == 0xffff
),出现“错误字符范围”错误。
@strangefeatures:是的,IIRC 被认为是re
库中的“wontfix”错误,因为 3.3 Unicode 更改使其无关紧要,并且因为 UTF-16 没有简单的修复。我会更新答案来解释,但没有人会喜欢这个解决方案……
@strangefeatures: (另外,我相信我们应该在 2.7/3.2 中让 regex
替换 re
,这本来可以为你处理这个问题,但后来它被推迟到 3.3 ,然后是 3.4,然后是无限期……)【参考方案2】:
我的解决方案包括emoji
和regex
模块。正则表达式模块支持识别字素簇(Unicode 代码点序列呈现为单个字符),因此我们可以计算一次像???? 这样的表情符号,尽管它由 4 个表情符号组成。
import emoji
import regex
def split_count(text):
emoji_counter = 0
data = regex.findall(r'\X', text)
for word in data:
if any(char in emoji.UNICODE_EMOJI for char in word):
emoji_counter += 1
# Remove from the given text the emojis
text = text.replace(word, '')
words_counter = len(text.split())
return emoji_counter, words_counter
测试:
line = "hello ??? emoji hello ???? how are ? you today????"
counter = split_count(line)
print("Number of emojis - , number of words - ".format(counter[0], counter[1]))
输出:
Number of emojis - 5, number of words - 7
【讨论】:
UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal if any(char in emoji.UNICODE_EMOJI for char in word):
错误
更简单:for word in data: if emoji.is_emoji(word): ...
【参考方案3】:
如果您尝试读取 ascii 范围之外的 unicode 字符,请不要将 转换为 ascii 范围。只需将其保留为 unicode 并从那里开始工作(未经测试):
import sys
count = 0
emoticons = set(range(int('1f600',16), int('1f650', 16)))
for row in sys.stdin:
for char in row:
if ord(char) in emoticons:
count += 1
print "%d emoticons found" % count
不是最好的解决方案,但应该可以。
【讨论】:
以上是关于如何使用python在字符串中查找和计算表情符号?的主要内容,如果未能解决你的问题,请参考以下文章
《现代命令行工具指南》15.表情符号:在命令行中查找表情符号 - emoj
《现代命令行工具指南》15.表情符号:在命令行中查找表情符号 - emoj
《现代命令行工具指南》15.表情符号:在命令行中查找表情符号 - emoj