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

时间:2018-08-21 11:06:25

标签: php regex unicode preg-replace unicode-escapes

anubhava's answer about matching ranges of unicode characters导致我使用正则表达式来清理特定范围的单个代码点字符。有了它,现在我可以使用以下简单表达式匹配所有miscellaneous symbols in this list(包括表情符号):

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

但是,我也想匹配此list of paired/double surrogates emoji中的那些,但要匹配nhahtdh explained in a comment

  

d800dfff的范围可以在UTF-16中指定代理,以允许指定更多字符。 单个代理在UTF-16中不是有效字符(必须有一对来指定有效字符)。

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

preg_replace('/\x{D83D}\x{DE00}/u', '', $str);

仅替换paired surrogates on this list中的第一个,即:

PHP抛出此错误:

  

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

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

我在这里错过任何“转义”替代吗?

1 个答案:

答案 0 :(得分:3)

revo's comment above对于找到解决方案非常有帮助:

  

如果您的PHP未随附针对UTF-16的PCRE版本,则无法执行此类匹配。 从PHP 7.0起,您可以按照以下语法\u{XXXX}使用Unicode代码点,例如preg_replace("~\u{1F600}~", '', $str);(注意双引号

由于我使用的是PHP 7,因此根据此PHP RFC page on unicode escapeecho "\u{1F602}";输出。该建议实质上是:

  

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

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

这意味着preg_replace中的匹配字符串(通常将单引号用于避免弄乱双引号字符串变量扩展)现在需要一些preg_quote magic。这是我想出的解决方案:

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

这里是proof of the above in 3v4l

编辑:更简单的解决方案

another comment made by revo中,似乎通过将unicode字符直接放入正则表达式字符类中,可以支持单引号字符串和以前的PHP版本(例如4.3.4):

preg_replace('/[☀-⛿-]/u','YOINK',$str);

要使用PHP 7's new feature though,您仍然需要双引号:

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

这里是revo's proof in 3v4l