Reputation: 750
While I was working with emojis and attempting to acquire their codepoint and names with the unicodedata
module, I kept having issues with multi-character emojis. The module refuses to let me use strings and instead wanted characters. I tried normalizing, I tried encoding in utf-8
and unicode-escape
, and I researched it again and again, but I was not successful in finding what was going on!
emojis = ["๐", "๐", "๐", "๐", "โฃ๏ธ", "โจ"]
for emoji in emojis:
codepoint: str = hex(ord(emoji))
filename = 'emoji_u{0}.png'.format(codepoint[2:])
print('{emoji} ({codepoint}) => {filename}'.format(emoji=emoji,
codepoint=codepoint,
filename=filename))
While yes, the above code does not use the unicodedata
module, it shows you what I was having a problem with regardless...
๐ (0x1f496) => emoji_u1f496.png
๐ (0x1f498) => emoji_u1f498.png
๐ (0x1f49d) => emoji_u1f49d.png
๐ (0x1f49e) => emoji_u1f49e.png
Traceback (most recent call last):
File "F:/Programming/Languages/Vue.js/lovely/collect.py", line 8, in <module>
codepoint: str = hex(ord(emoji))
TypeError: ord() expected a character, but string of length 2 found
After a break, somehow, I managed to convert the emoji unintentionally, from this: โฃ๏ธ
to this: โฃ
. Python was able to process this new emoji character perfectly fine. The unicodedata
module likes it too!
So what's the difference? Why does one have color and not the other in both my browser and IDE? And most importantly, how do I convert multi-character emojis to single-character emojis in Python?
Upvotes: 1
Views: 1611
Reputation: 177971
Some human-perceived single-character emoji (called graphemes) are made up of multiple code points. Here's a way to handle them. I added a complicated example:
import unicodedata as ud
emojis = ["๐", "๐", "๐", "๐", "โฃ๏ธ", "โจ", "๐จโ๐ฉโ๐งโ๐ฆ"]
for emoji in emojis:
print('Emoji:',emoji)
for cp in emoji:
print(f' {cp} U+{ord(cp):04X} {ud.name(cp)}')
Output:
Emoji: ๐
๐ U+1F496 SPARKLING HEART
Emoji: ๐
๐ U+1F498 HEART WITH ARROW
Emoji: ๐
๐ U+1F49D HEART WITH RIBBON
Emoji: ๐
๐ U+1F49E REVOLVING HEARTS
Emoji: โฃ๏ธ
โฃ U+2763 HEAVY HEART EXCLAMATION MARK ORNAMENT
๏ธ U+FE0F VARIATION SELECTOR-16
Emoji: โจ
โจ U+2728 SPARKLES
Emoji: ๐จโ๐ฉโ๐งโ๐ฆ
๐จ U+1F468 MAN
โ U+200D ZERO WIDTH JOINER
๐ฉ U+1F469 WOMAN
โ U+200D ZERO WIDTH JOINER
๐ง U+1F467 GIRL
โ U+200D ZERO WIDTH JOINER
๐ฆ U+1F466 BOY
If the emoji are in a single string the rules for processing a single grapheme are complicated, but implemented by the 3rd party regex
module. \X
matches graphemes:
import unicodedata as ud
import regex
for m in regex.finditer(r'\X', '๐๐๐๐โฃ๏ธโจ๐จโ๐ฉโ๐งโ๐ฆ'):
emoji = m.group(0)
print(f'{emoji} {ascii(emoji)}')
Output:
๐ '\U0001f496'
๐ '\U0001f498'
๐ '\U0001f49d'
๐ '\U0001f49e'
โฃ๏ธ '\u2763\ufe0f'
โจ '\u2728'
๐จโ๐ฉโ๐งโ๐ฆ '\U0001f468\u200d\U0001f469\u200d\U0001f467\u200d\U0001f466'
Upvotes: 6