¿Cómo encontrar y contar los emoticones en una cadena usando python?

Este tema se ha tratado para los emoticones basados ​​en texto en link1 , link2 , link3 . Sin embargo, me gustaría hacer algo ligeramente diferente a emparejar emoticons simples. Estoy clasificando los tweets que contienen los icons de los emoticones. La siguiente información de Unicode contiene solo estos emoticones: pdf .

Usando una cadena con palabras en inglés que también contiene cualquiera de estos emoticons del pdf , me gustaría poder comparar el número de emoticons con el número de palabras.

La dirección en la que me dirigía hacia abajo no parece ser la mejor opción y estaba buscando ayuda. Como puede ver en la secuencia de comandos a continuación, estaba planeando hacer el trabajo desde la línea de comandos:

$cat  | ./emo.py 

emo.py psuedo script:

 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 

El problema que estoy encontrando es la deencoding / encoding. No he encontrado una buena opción sobre cómo codificar / decodificar la cadena para poder encontrar correctamente los icons. Un ejemplo de la cadena que deseo buscar para encontrar el número de palabras y emoticons es el siguiente:

“¡Smiley emoticon mece! introduzca la descripción de la imagen aquí me gustas introduzca la descripción de la imagen aquí . ”

El desafío: ¿puedes hacer un script que cuente la cantidad de palabras y emoticons en esta cadena? Observe que los emoticones están sentados junto a las palabras sin espacio entre ellas.

Related of "¿Cómo encontrar y contar los emoticones en una cadena usando python?"

Primero, no hay necesidad de codificar aquí en absoluto. Tienes una cadena Unicode, y el motor de re puede manejar Unicode, así que solo úsalo.

Una clase de caracteres puede incluir un rango de caracteres, especificando el primero y el último con un guión en medio. Y puede especificar caracteres Unicode que no sabe cómo escribir con secuencias de escape \U Asi que:

 import re s=u"Smiley emoticon rocks!\U0001f600 I like you.\U0001f601" count = len(re.findall(ru'[\U0001f600-\U0001f650]', s)) 

O bien, si la cadena es lo suficientemente grande como para findall lista completa de findall es inútil:

 emoticons = re.finditer(ru'[\U0001f600-\U0001f650]', s) count = sum(1 for _ in emoticons) 

Contando palabras, puedes hacerlo por separado:

 wordcount = len(s.split()) 

Si desea hacerlo todo de una vez, puede usar un grupo de alternancia:

 word_and_emoticon_count = len(re.findall(ru'\w+|[\U0001f600-\U0001f650]', s)) 

Como @strangefeatures señala, las versiones de Python anteriores a 3.3 permitían comstackciones “Unicode estrechas”. Y, por ejemplo, la mayoría de las comstackciones de Windows de CPython son estrechas. En construcciones estrechas, los caracteres solo pueden estar en el rango U+0000 a U+FFFF . No hay forma de buscar estos caracteres, pero está bien, porque no existen para buscar; solo puede asumir que no existen si aparece un error de “rango no válido” al comstackr la expresión regular.

Excepto, por supuesto, que hay una buena probabilidad de que de donde sea que obtengas tus cadenas reales, sean UTF-16-BE o UTF-16-LE, de modo que los caracteres existan, simplemente están codificados en pares sustitutos . Y quieres emparejar esos pares sustitutos, ¿verdad? Así que necesitas traducir tu búsqueda en una búsqueda de pares sustitutos. Es decir, convierta sus puntos de código alto y bajo en unidades de código de pares sustitutos, luego (en términos de Python) busque:

 (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) 

Puede omitir la segunda condición en el último caso si no le preocupa aceptar el falso UTF-16.

Si no es obvio cómo se traduce en [\U0001e050-\U0001fbbf] , aquí hay un ejemplo para el rango [\U0001e050-\U0001fbbf] en UTF-16-BE:

 (\ud838[\udc50-\udfff])|([\ud839-\ud83d].)|(\ud83e[\udc00-\udfbf]) 

Por supuesto, si su rango es lo suficientemente pequeño para que low_lead == high_lead esto se simplifique. Por ejemplo, el rango de la pregunta original se puede buscar con:

 \ud83d[\ude00-\ude50] 

Un último truco, si no sabe realmente si va a obtener UTF-16-LE o UTF-16-BE (y la lista de materiales está muy lejos de los datos que está buscando): Porque no hay un líder sustituto o la unidad de código de camino es válida como un carácter independiente o como el otro extremo de un par, solo puede buscar en ambas direcciones:

 (\ud838[\udc50-\udfff])|([\ud839-\ud83d][\udc00-\udfff])|(\ud83e[\udc00-\udfbf])| ([\udc50-\udfff]\ud838)|([\udc00-\udfff][\ud839-\ud83d])|([\udc00-\udfbf]\ud83e) 

Si está intentando leer caracteres Unicode fuera del rango de ascii, no convierta al rango de ascii. Solo déjelo como Unicode y trabaje desde allí (sin probar):

 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 

No es la mejor solución, pero debería funcionar.

Mi solución incluye los módulos emoji y regex . El módulo regex admite el reconocimiento de agrupaciones de grafemas (secuencias de puntos de código Unicode representados como un solo carácter), por lo que podemos contar los emojis como 👨‍👩‍👦‍👦 una vez, aunque consta de 4 emojis.

 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 

Pruebas:

 line = "hello 👩🏾‍🎓 emoji hello 👨‍👩‍👦‍👦 how are 😊 you today🙅🏽🙅🏽" counter = split_count(line) print("Number of emojis - {}, number of words - {}".format(counter[0], counter[1])) 

Salida:

 Number of emojis - 5, number of words - 7