【问题标题】:PHP: How to match a range of unicode paired surrogates emoticons/emoji?PHP:如何匹配一系列 unicode 配对代理表情符号/表情符号?
【发布时间】:2019-01-27 13:28:55
【问题描述】:

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:

在d800 到dfff 的范围内可以指定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 的。

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

【问题讨论】:

  • 您是否只是想构建一个正则表达式来匹配这 80 个表情符号并将其用作“硬编码”模式,或者您是否正在尝试编写将“转换”U+1F600 到 \x{D83D}\x{DE00} 的代码?
  • 哪个 PHP 版本?
  • @WiktorStribiżew 如果可能的话。 hardcoded 模式将是一个范围。
  • @revo PHP 7.1.5 及以上版本。
  • 如果您的 PHP 未附带针对 UTF-16 的 PCRE 构建,那么您将无法执行此类匹配。从 PHP 7.0 开始,您可以使用 Unicode 代码点,遵循此语法 \u{XXXX},例如preg_replace("~\u{1F600}~", '', $str);(注意双引号)

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


【解决方案1】:

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

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

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

为 双引号字符串 和 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。

【讨论】:

  • 我想补充一点,您既不需要 preg_quote 也不需要 PCRE 的 \x{XXXX} 语法。只需使用/[\u{2600}-\u{26FF}\u{1F600}-\u{1F64F}]/u。这等于/[☀-⛿?-?]/u。在此处查看现场演示3v4l.org/uA3mD
  • @revo 哈哈,这太棒了!直接放置字符允许在 PHP 4 中替换!我想这是最好的解决方案(如果 IDE 没有崩溃的话)。我用你的发现编辑了答案。非常感谢!
猜你喜欢
  • 2017-01-24
  • 2017-04-18
  • 2014-04-11
  • 2020-06-04
  • 1970-01-01
  • 2013-01-09
  • 2016-04-28
  • 2021-06-04
  • 1970-01-01
相关资源
最近更新 更多