php 7.4+ 中 preg_match_all('/\p{emoji}/u', $s, $matches) 是最直接的 emoji 匹配方式,支持 unicode 15.1 全量 emoji(含 zwj 组合、肤色修饰符等),但需 /u 修饰符且不包含 ✅❤️等 \p{so} 类符号。

preg_match_all('/\p{Emoji}/u', $s, $matches) 是最直接的写法
PHP 7.4+ 原生支持 \p{Emoji} 这类 Unicode 属性类,它能覆盖 Unicode 15.1 中定义的所有 emoji 字符(含扩展区如 ?、?、? 等),无需手动拼接码点范围。前提是必须加 /u 修饰符,否则 \p{} 会当作字面量处理,匹配失败。
常见错误现象:preg_match('/\p{Emoji}/', $s) 不加 /u 时永远返回 false;mb_ereg() 等旧函数根本不识别 \p{},直接报错或静默失败。
- 确保 PHP 版本 ≥ 7.4(
php -v验证),低版本会提示 “Unknown property name” 错误 -
\p{Emoji}包含 ZWJ 组合(如 ??)、肤色修饰符(??)、以及新增的 Unicode 扩展区 emoji,但不包含 emoji-style 的符号(如 ✅、❤️)——它们属于\p{So}(Symbol, other) - 若需同时捕获 emoji 和 emoji-style 符号,用
/[\p{Emoji}\p{So}]/u,但注意\p{So}会混入 ❌⚠️等非 emoji 符号,需后置过滤
兼容旧版 PHP(
PHP 7.3 及更早版本不解析 \p{Emoji},必须显式列出扩展区码点。Unicode 扩展区 emoji 主要分布在:
\x{1F900}-\x{1F9FF}(Supplemental Symbols and Pictographs)、\x{1FA00}-\x{1FA6F}(Symbols and Pictographs Extended-A)、\x{1FAC0}-\x{1FACF}(Symbols and Pictographs Extended-B)——这些是 2022–2024 年新增的主流扩展区。
- 不要只写
/[\x{1F600}-\x{1F64F}]/u,它漏掉全部扩展区,比如 ?(U+1FAE7)根本匹配不到 - 组合 emoji(如 ??)需额外包含
\x{200D}(ZWJ)和\x{FE0F}(emoji variation selector),否则会被拆成碎片 - 正则中多个范围要用
|或连续写,例如:/[\x{1F600}-\x{1F64F}\x{1F900}-\x{1F9FF}\x{1FA00}-\x{1FA6F}\x{1FAC0}-\x{1FACF}\x{200D}\x{FE0F}]/u
匹配完整 emoji 序列(不是单个码点)要用 \X 或自定义组合模式
\X 能匹配一个 Unicode 字形簇(grapheme cluster),对 ??、??、?♂️ 这类多码点 emoji 天然友好,但它也会把普通文字(如“你好”)按字形切开,不适合纯 emoji 提取场景。
真正要「提取完整 emoji」而非「拆解字符」,得用带 ZWJ 和 variation selector 的组合正则:
preg_match_all('/(?:[\x{1F600}-\x{1F64F}\x{1F900}-\x{1F9FF}\x{1FA00}-\x{1FA6F}\x{1FAC0}-\x{1FACF}]|\x{200D}|\x{FE0F})+/u', $s, $matches);
- 这个模式优先捕获连续的 emoji 码点 + ZWJ + variation selector,避免把 ?? 拆成三个独立字符
- 仍可能误吞紧跟 emoji 的标点(如 ?!),如需严格隔离,加边界断言:
/(? -
\X在 PHP 8.2+ 对 emoji 支持更稳,但在 7.x 中对某些新 emoji(如 ? U+1FAC6)可能切分不准,实测不如显式范围可靠
数据库和输入源编码不匹配会导致正则完全失效
即使正则写对了,preg_match_all() 返回空数组,大概率是字符串本身已损坏——比如 MySQL 用 utf8 而非 utf8mb4 存储,导致 4 字节 emoji 被截断为 ;或前端 POST 数据没设 Content-Type: text/plain; charset=utf-8,PHP 接收时默认 ISO-8859-1 解码。
- 检查
mb_internal_encoding()是否为'UTF-8',不是就mb_internal_encoding('UTF-8')强制设 - 验证输入字符串是否真含 emoji:
var_dump(bin2hex($s));看是否有f09f...开头的 4 字节序列 - 从数据库读取后,用
mb_convert_encoding($s, 'UTF-8', 'UTF-8')强制重编码(防 meta 信息丢失),再喂给正则
Unicode 扩展区 emoji 的码点越来越分散,靠人工维护范围迟早漏掉,\p{Emoji} 是唯一可持续方案——但你得确认运行环境真支持它,而不是文档里写着“支持”实际却 fallback 到旧 PCRE 库。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











