php找到表情符号[更新现有代码]

时间:2012-05-12 13:13:29

标签: php regex unicode emoji

我正在尝试在我的php代码中检测表情符号,并阻止用户输入它。

我的代码是:

if(preg_match('/\xEE[\x80-\xBF][\x80-\xBF]|\xEF[\x81-\x83][\x80-\xBF]/', $value) > 0)
{
    //warning...
}

但不适用于所有表情符号。有什么想法吗?

5 个答案:

答案 0 :(得分:10)

if(preg_match('/\xEE[\x80-\xBF][\x80-\xBF]|\xEF[\x81-\x83][\x80-\xBF]/', $value) 

您确实希望在字符级别匹配Unicode,而不是尝试跟踪UTF-8字节序列。使用u修饰符以字符为基础处理您的UTF-8字符串。

表情符号在块U + 1F300-U + 1F5FF中编码。但是:

  • 来自日本航空公司的许多角色' 'emoji'集实际上映射到现有的Unicode符号,例如卡套装,十二生肖和一些箭头。你现在把这些符号算作“表情符号”吗?

  • 仍有系统不使用新标准化的Unicode表情符号代码点,而是使用私有使用区域中的ad-hoc范围。每个运营商都有自己的编码。 iOS 4使用了Softbank集。 More info.您可能希望阻止整个私人使用区。

例如:

function unichr($i) {
    return iconv('UCS-4LE', 'UTF-8', pack('V', $i));
}

if (preg_match('/['.
    unichr(0x1F300).'-'.unichr(0x1F5FF).
    unichr(0xE000).'-'.unichr(0xF8FF).
']/u'), $value) {
    ...
}

答案 1 :(得分:2)

来自维基百科:

  

从Unicode 6.0开始设置的核心表情符号由722个字符组成   其中114个字符映射到一个或多个字符的序列   6.0之前的Unicode标准,其余608个字符映射到   Unicode 6.0中引入的一个或多个字符的序列。[4]   没有专门为表情符号预留块 - 新符号   被编码在七个不同的块(一些新创建的)中,并在那里   存在一个名为EmojiSources.txt的Unicode数据文件,其中包含   与日本供应商的遗留字符集之间的映射。

这是mapping file。文件中有722行,每行代表722个表情符号中的一个。

这似乎不是一件容易的事,因为没有为表情符号预留特定的块。您需要调整正则表达式以涵盖所有表情符号unicodes。

您可以像这样匹配单个unicode:

\x{1F30F}

1F30F是地球表情符号的unicode。

对不起,我没有给你一个完整的答案,但这应该让你朝着正确的方向前进。

答案 2 :(得分:1)

正确的答案是检测Miscellaneous_Symbols_And_Pictographs块中指定代码点的位置。在Perl中,您将使用

 /\p{Assigned}/ && \p{block=Miscellaneous_Symbols_And_Pictographs}/

或只是

/\P{Cn}/ && /\p{Miscellaneous_Symbols_And_Pictographs}/

你应该将它们与

组合成一个模式
/(?=\p{Assigned})\p{Miscellaneous_Symbols_And_Pictographs}/

我不记得PHP使用的PCRE库是否允许您访问必需的Unicode字符属性。我的回忆是,在那个特定区域它很弱。我认为你只有Unicode脚本属性和一般类别。叹息。

有时你只需要使用真实的东西。

由于缺乏合适的Unicode支持,您可能必须自己枚举该块:

/(?=\P{Cn})[\x{1F300}-\x{1F5FF}]/

看起来像是一场维护噩梦,充满了神奇的数字。

答案 3 :(得分:0)

这是我的解决方案,它是一个更简单的(感谢 php7)版本的 bobince's 答案。

<?php
if (preg_match("/[\u{1f300}-\u{1f5ff}\u{e000}-\u{f8ff}]/u", $text)) {
  // echo "? oh no. Emojis not allowed!";
}

EDIT 根据 bobnice 的回答的建议,此正则表达式排除了实际的表情符号范围 (1f300 - 1f5ff) 和 bobnice 提出的您可能感兴趣的其他范围在阻塞中。

EDIT 2 要明确:这种更简单的格式在 PHP 7.0+ 中是可能的。如果您仍在使用(现在不受支持)版本的 PHP,则需要使用原始答案。

答案 4 :(得分:-2)

这就是我今天想出来的。对于这个问题,它可能不是一个好的解决方案,但至少它可以工作;)

if(iconv('Windows-1250', 'UTF-8', iconv('UTF-8', 'Windows-1250', $value)) != $value)