如何判断字符串是否以 emoji 开头并获取首个 emoji(不使用正则表达式)
非正则式的Emoji解析方案(含首Emoji判断)
一、为什么不用正则?
正则靠匹配字符范围识别Emoji,但Unicode的Emoji体系复杂:不仅有单码点的基础Emoji,还有带肤色修饰符的序列、零宽连接符(U+200D)组合的复合Emoji(比如👨👩👧),而且每年都会新增Emoji。操作系统和浏览器都是基于Unicode字符属性来解析的,而非正则——这种方式能直接跟随标准更新,无需频繁调整匹配规则。
二、算法式Emoji识别/提取的核心逻辑
基于Unicode官方定义的Emoji属性体系,核心步骤:
- 识别基础Emoji:判断字符的Unicode类别(如
So=其他符号、Lo=其他字母),或通过字符名称是否包含"EMOJI"标记来确认。 - 处理修饰序列:如果基础Emoji后跟随肤色修饰符(U+1F3FB~U+1F3FF),合并为一个完整Emoji。
- 处理复合序列:如果遇到零宽连接符(U+200D),检查后续字符是否为合法Emoji组件,若是则继续合并,直到序列结束。
代码实现(Python)
import unicodedata def is_emoji_component(c): """判断是否为Emoji组件(修饰符、零宽连接符等)""" cat = unicodedata.category(c) # 肤色修饰符属于Sk类别(符号-修饰符) if cat == 'Sk' and 0x1F3FB <= ord(c) <= 0x1F3FF: return True # 零宽连接符是Cf类别(格式字符) if c == '\u200D': return True # 性别符号等其他组件可按需扩展 return False def extract_emojis(s): """提取字符串中所有完整Emoji""" emojis = [] i, n = 0, len(s) while i < n: current_char = s[i] # 判断是否为基础Emoji:类别为So/Lo且名称含EMOJI char_cat = unicodedata.category(current_char) if char_cat in ('So', 'Lo') and 'EMOJI' in unicodedata.name(current_char, ''): current_emoji = [current_char] i += 1 # 处理后续组件 while i < n: next_char = s[i] if is_emoji_component(next_char): current_emoji.append(next_char) i += 1 # 零宽连接符后必须跟合法Emoji才继续合并 if next_char == '\u200D': if i >= n or not (unicodedata.category(s[i]) in ('So', 'Lo') and 'EMOJI' in unicodedata.name(s[i], '')): break else: break emojis.append(''.join(current_emoji)) else: i += 1 return emojis
三、判断字符串是否以Emoji开头并获取首个Emoji
基于上述逻辑,只需从字符串起始位置开始解析:
def get_first_emoji(s): """获取字符串中的首个完整Emoji,无则返回None""" if not s: return None current_char = s[0] char_cat = unicodedata.category(current_char) if char_cat not in ('So', 'Lo') or 'EMOJI' not in unicodedata.name(current_char, ''): return None # 构建完整的首个Emoji序列 current_emoji = [current_char] i, n = 1, len(s) while i < n: next_char = s[i] if is_emoji_component(next_char): current_emoji.append(next_char) i += 1 if next_char == '\u200D': if i >= n or not (unicodedata.category(s[i]) in ('So', 'Lo') and 'EMOJI' in unicodedata.name(s[i], '')): break else: break return ''.join(current_emoji) def starts_with_emoji(s): """判断字符串是否以Emoji开头""" return get_first_emoji(s) is not None
说明
这种方案完全模拟了系统级的Emoji解析逻辑:依赖Unicode标准的字符属性而非固定的字符范围,能自动兼容新增的Emoji和复杂组合序列,比正则更健壮、易维护。
内容的提问来源于stack exchange,提问作者Mike Tsayper
相关产品推荐
相关产品推荐

