5

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

我的代码是:

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

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

4

5 回答 5

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 块中编码。然而:

  • 日本运营商的“表情符号”集中的许多字符实际上都映射到现有的 Unicode 符号,例如卡片套装、十二生肖和一些箭头。你现在把这些符号算作“表情符号”了吗?

  • 仍然有一些系统不使用新标准化的 Unicode 表情符号代码点,而是在私人使用区域中使用临时范围。每个运营商都有自己的编码。iOS 4 使用了 Softbank 套件。更多信息。您可能希望封锁整个私人使用区。

例如:

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) {
    ...
}
于 2012-05-14T13:41:19.797 回答
2

来自维基百科:

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

这是映射文件。文件中有 722 行,每行代表 722 个表情符号之一。

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

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

\x{1F30F}

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

抱歉,我没有给你完整的答案,但这应该会让你朝着正确的方向前进。

于 2012-05-12T17:58:00.060 回答
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}]/

对我来说,这就像一场维护噩梦,充满了神奇的数字。

于 2012-05-13T01:00:36.790 回答
0

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

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

编辑按照 bobnice 的回答的建议,这个正则表达式既排除了实际的表情符号范围(1f300- 1f5ff),也排除了 bobnice 提出的您可能有兴趣阻止的其他范围。

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

于 2021-01-19T14:20:29.390 回答
-2

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

if(iconv('Windows-1250', 'UTF-8', iconv('UTF-8', 'Windows-1250', $value)) != $value)
于 2012-05-13T13:45:02.237 回答