查找PHP表情符号[更新现有代码]

5

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

我现有的代码是:

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

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

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

你应该使用 u 修饰符以字符为基础处理你的UTF-8字符串,而不是尝试跟踪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) {
    ...
}

你好,感谢你的想法,但它并不适用于所有表情符号 :) 有没有办法添加对这个表情符号的支持:❤?还有可能是其他一些表情符号吗?现在它已经完美地适用于iOS表情符号。谢谢。 - Kukosk
2
那就是关于你如何定义表情符号的问题。❤在任何人构思表情符号之前就已经存在作为一般符号了。如果你想要屏蔽只被重新用作表情符号的符号,请查看上面的 Emoji For PHP 链接并挑选出所有使用的 U+2xxx 代码点。或者,如果你不需要它们,可以考虑屏蔽更广泛的符号范围,例如 unichr(0x2190).'-'.unichr(0x27FF) - bobince

2

根据维基百科,Unicode 6.0版的核心表情符号集包括722个字符,其中114个字符映射到早期版本的Unicode标准中一个或多个字符的序列,其余608个字符映射到在Unicode 6.0中引入的一个或多个字符的序列。没有专门为表情符号设置的块 - 新符号编码在七个不同的块中(有些是新创建的),并存在一个名为EmojiSources.txt的Unicode数据文件,其中包括与日本供应商的遗留字符集之间的映射。

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

由于没有专门为表情符号设置的块,因此似乎这不是一件容易的事情。您需要调整正则表达式以涵盖所有表情符号Unicode。

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

\x{1F30F}

1F30F是一个地球表情符号的Unicode编码。

很抱歉我没有完整的答案,但这应该能帮助你朝着正确的方向前进。


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}]/

对我来说,这看起来像是一个充满魔法数字的维护噩梦。


序列在偏移量19处太大 :( - Kukosk
@Kukosk 我不知道那是什么意思。这是一个合法的范围。你不能将表情符号范围指定为/[\x{1F300}-\x{1F5FF}]/]吗? - tchrist
现在它可以工作了...但无法识别所有的表情符号 :( 当我使用iOS“Emoji”键盘上的表情符号时,它无法检测到它们... - Kukosk

1
这是我的解决方案,它是 bobince 答案的简化版本(感谢php7)。
<?php
if (preg_match("/[\u{1f300}-\u{1f5ff}\u{e000}-\u{f8ff}]/u", $text)) {
  // echo " oh no. Emojis not allowed!";
}


根据bobnice的建议,这个正则表达式排除了实际的emoji范围(1f300 - 1f5ff)和bobnice提出的另一个你可能想要阻止的范围。
需要明确的是:在PHP 7.0+中可以使用这种更简单的格式。如果您仍在使用(现在不受支持的)旧版本的PHP,则需要使用原始答案。

这个答案缺少教育性的解释。Bobince的答案有解释并不是在这里不提供解释的借口。 - mickmackusa
@mickmackusa 真的吗?在同一页内链接到当前被接受的答案?我认为尊重其他贡献者已经做得很好了,不应该复制粘贴或重新陈述他们的内容,并且应该表彰他们的功劳。我认为人们应该阅读bobnice的答案;这只是php7.0+的一个方便更新。 - artfulrobot
然后解释一下你的答案为什么更现代/更简单。解释一下为什么有人应该使用你的而不是Bobince的。需要提供比代码片段和链接更多的内容。 - mickmackusa
或者,如果你只是想提供一个更新的正则表达式模式,你可以在bobince的回答下留言...但我假设你想为你的贡献获得声望分,所以最好发布一个完整且解释清楚的答案。 - mickmackusa
我认为我在我的开头句子中已经做到了这一点,但如果有点晦涩难懂,现在我已经明确解释了。我并不是非常在意积分,但我为了让SE对我(我经常找到自己的问题!)和其他人有用而做出贡献。你说得对,在一个帖子中包含所有信息是最方便的方式。 - artfulrobot

-2
今天我想出了这个解决方案,虽然可能不是针对这个问题的最佳解决方案,但它至少可行;)
if(iconv('Windows-1250', 'UTF-8', iconv('UTF-8', 'Windows-1250', $value)) != $value)

3
你正在使用微软吗?这可能是个 bug:微软在处理 Unicode 时有很多问题,尤其是在需要处理表情符号的完整 Unicode 范围之外,因为它们超出了 BMP。你应该在标签中加入 WINDOWS。难道你不能使用普通的 Unix 系统代替吗?考虑到它们的标准兼容性,Mac 也很便宜,并且这正是你在这里所需要的。Linux 更便宜。 - tchrist
我发现这不是一个好的“解决方法”...它不能处理英镑符号和其他一些字符... - Kukosk
Windows-1250的转换建议不同。但我认为这不是你需要调用iconv的问题。也许我误解了问题。 - tchrist
应该按照您所说的方式(不使用iconv()调用),但是我不知道如何在php中实现...我只想检测字符串中的表情符号,并让用户知道他们必须将其删除 :) - Kukosk
1
这将删除在cp1250中欧洲无法编码的所有内容。这肯定会删除表情符号,但也会删除绝大部分Unicode字符... - bobince

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接