PHP:如何匹配一系列 unicode 配对代理表情符号/表情符号?

CPH*_*hon 0 php regex unicode preg-replace unicode-escapes

anubhava关于匹配 unicode 字符范围的回答使我使用正则表达式来清理特定范围的单个代码点字符。有了它,现在我可以用这个简单的表达式匹配这个列表中的所有杂项(包括表情符号):

preg_replace('/[\x{2600}-\x{26FF}]/u', '', $str);
Run Code Online (Sandbox Code Playgroud)

但是,我也想匹配这个配对/双代理表情符号列表中的那些,但正如nhahtdh 在评论中解释的那样:

有一个范围从d800到dfff指定 UTF-16 中的代理,以允许指定更多字符。甲单个替代不在UTF-16是有效的字符(一对是必要指定一个有效字符)。

因此,例如,当我尝试这样做时:

preg_replace('/\x{D83D}\x{DE00}/u', '', $str);
Run Code Online (Sandbox Code Playgroud)

仅替换此列表中配对代理中的第一个,即:

PHP抛出这个:

preg_replace(): 编译失败: 不允许的 Unicode 代码点 (>= 0xd800 && <= 0xdfff)

我尝试了几种不同的组合,包括UTF8 中上述代码点的假定组合( '/[\x{00F0}\x{009F}\x{0098}\x{0080}]/u'),但我仍然无法匹配它。我还研究了其他PCRE 模式修饰符,但它似乎u是唯一允许指向 UTF8 的修饰符。

我在这里错过了任何“逃生”选择吗?

CPH*_*hon 5

上面 revo 的评论对找到解决方案非常有帮助:

如果您的 PHP 未附带针对 UTF-16 的 PCRE 构建,那么您将无法执行此类匹配。从 PHP 7.0 开始,您可以使用遵循此语法的 Unicode 代码点,\u{XXXX}例如preg_replace("~\u{1F600}~", '', $str);(注意双引号)

由于我使用的是 PHP 7,echo "\u{1F602}";因此根据unicode escape上的这个PHP RFC 页面输出。这个提议的本质是:

为双引号字符串和heredoc添加了新的转义序列。

  • \u{ codepoint-digits }其中codepoint-digits由十六进制数字组成。

这意味着匹配的字符串preg_replace(通常是单引号,以免与双引号字符串变量扩展混淆),现在需要一些preg_quote 魔法。这是我想出的解决方案:

preg_replace(
  // single point unicode list
  "/[\x{2600}-\x{26FF}".
  // http://www.fileformat.info/info/unicode/block/miscellaneous_symbols/list.htm
  // concatenates with paired surrogates
  preg_quote("\u{1F600}", '/')."-".preg_quote("\u{1F64F}", '/').
  // https://www.fileformat.info/info/unicode/block/emoticons/list.htm
  "]/u",
  '',
  $str
);
Run Code Online (Sandbox Code Playgroud)

这是3v4l 中上述内容的证明。

编辑:一个更简单的解决方案

在revo 发表的另一条评论中,似乎通过将 unicode 字符直接放入正则表达式字符类中,可以支持单引号字符串和以前的 PHP 版本(例如 4.3.4):

preg_replace('/[?-?-]/u','YOINK',$str);
Run Code Online (Sandbox Code Playgroud)

但是为了使用PHP 7 的新特性,你仍然需要双引号:

preg_replace("/[\u{2600}-\u{26FF}\u{1F600}-\u{1F64F}]/u",'YOINK',$str);
Run Code Online (Sandbox Code Playgroud)

这是revo 在 3v4l 中的证明。