如何使用python在字符串中查找和计算表情符号?

时间:2013-10-03 00:57:24

标签: python regex string unicode

此主题已针对link1link2link3的基于文字的表情符号进行了处理。但是,我想做一些与匹配简单表情符号略有不同的东西。我正在整理包含表情符号图标的推文。以下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

我遇到的问题是解码/编码。我还没有找到一个如何编码/解码字符串的好选项,所以我可以正确找到图标。我想搜索以查找单词和表情符号数量的字符串示例如下:

“笑脸表情岩!enter image description here我喜欢你enter image description here。”

挑战:你能制作一个计算此字符串中单词和表情符号数量的脚本吗?请注意,表情符号都位于单词旁边,两者之间没有空格。

3 个答案:

答案 0 :(得分:15)

首先,根本不需要编码。你有一个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+0000U+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,你可以在最后一种情况下放弃第二个条件。

如果将其转换为regexp并不明显,这里是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)

答案 1 :(得分:0)

如果您尝试读取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

不是最好的解决方案,但应该可行。

答案 2 :(得分:0)

我的解决方案包括emojiregex模块。正则表达式模块支持识别字形集群(呈现为单个字符的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