这些Unicode组合字符有什么用处,我们如何过滤它们?

时间:2012-05-02 13:34:24

标签: unicode sanitize combining-marks zalgo

กิิิิิิิิิิิิิิิิิิิิก้้้้้้้้้้้้้้้้้้้้ก็็็็็็็็็็็็็็็็็็็็ก็็็็็็็็็็็็็็็็็็็็กิิิิิิิิิิิิิิิิิิิิก้้้้้้้้้้้้้้้้้้้้ก็็็็็็็็็็็็็็็็็็็็กิิิิิิิิิิิิิิิิิิิิก้้้้้้้้้้้้้้้้้้้้กิิิิิิิิิิิิิิิิิิิิก้้้้้้้้้้้้้้้้้้้้ก็็็็็็็็็็็็็็็็็็็็ก็็็็็็็็็็็็็็็็็็็็กิิิิิิิิิิิิิิิิิิิิก้้้้้้้้้้้้้้้้้้้้ก็็็็็็็็็็็ ็็็็็็็็กิิิิิิิิิิิิิิิิิิิิก้้้้้้้้้้้้้้้้้้้้

这些最近出现在Facebook评论栏目中。

我们如何消毒这个?

4 个答案:

答案 0 :(得分:79)

  

这些unicode角色是什么?

这是一个有一系列combining characters的角色。因为所讨论的组合字符想要超过基本字符,所以它们会叠加(字面意思)。例如,

的情况

ก้้้้้้้้้้้้้้้้้้้้

...它是一个ก(泰语字符 ko kai )(U+0E01)后跟20个泰语组合字符 mai tho U+0E49)。

  

我们如何消毒这个?

可以预处理文本并限制可以应用于单个角色的组合字符的数量,但这些努力可能不值得奖励。您需要所有当前字符的数据表,以便您知道它们是组合还是什么,并且您需要确保至少允许少数几个,因为某些语言是用单个基础上的几个变音符号。现在,如果您想将注释限制为拉丁字符集,那么这将是一个更容易的范围检查,但当然,如果您想将注释限制为几种语言,那么这只是一个选项。有关unicode.org的更多信息,代码表等。

顺便说一下,如果你想知道一些角色是如何编写的,那么就在最近的另一个问题我在JSBin上编写了一个quick-and-dirty "Unicode Show Me" page。您只需将文本复制并粘贴到文本区域,它就会显示文本所构成的所有代码点(〜字符),以及描述每个字符的页面上方的链接。它只适用于U + FFFF及以下范围内的代码点,因为它是用JavaScript编写的,并且在JavaScript中处理U + FFFF以上的字符时,你必须完成比我想要做的更多的工作(因为在JavaScript中,"字符" 总是 16位,这意味着对于某些语言,字符可以分成两个单独的JavaScript"字符"而且我没有&# 39; t考虑到这一点),但对大多数文本来说都很方便......

答案 1 :(得分:18)

如果你有一个具有良好Unicode支持的正则表达式引擎,那么清理这种字符串是微不足道的。例如,在Perl中,您可以从每个(用户感知的)字符中删除除第一个组合标记之外的所有标记,如下所示:

#!/usr/bin/perl
use strict;
use utf8;

binmode(STDOUT, ':utf8');

my $string = "กิิ ก้้ ก็็ ก็็ กิิ ก้้ ก็็ กิิ ก้้ กิิ ก้้ ก็็ ก็็ กิิ ก้้ ก็็ กิิ ก้้";
$string =~ s/(\p{Mark})\p{Mark}+/$1/g; # Strip excess combining marks
print("$string\n");

这将打印:

กิก้ก็ก็กิก้ก็กิก้กิก้ก็ก็กิก้ก็กิก้

答案 2 :(得分:12)

“我们如何消毒这个”最好由T.J Crowder

回答

但是,我认为清理是错误的方法,而Cristy在包含css的元素上使用overflow:hidden是正确的。

至少,这就是我解决它的方式。

答案 3 :(得分:7)

好的,这个花了我一段时间才弄明白,我觉得组合角色来制作zalgo是limited to these。所以我期待following regex抓住这些怪人。

([\u0300–\u036F\u1AB0–\u1AFF\u1DC0–\u1DFF\u20D0–\u20FF\uFE20–\uFE2F]{2,})

它不起作用......

问题在于list in wiki并未涵盖所有组合字符。

是什么给了我一个提示是"ก้้้้้้้้้้้้้้้้้้้้".charCodeAt(2).toString(16) =“e49”,它不属于合并范围,属于“私人使用”。

在C#中,它们属于UnicodeCategory.NonSpacingMark,后面的脚本会将它们刷新:

    [Test]
    public void IsZalgo()
    {
        var zalgo = new[] { UnicodeCategory.NonSpacingMark };

        File.Delete("IsModifyLike.html");
        File.AppendAllText("IsModifyLike.html", "<table>");
        for (var i = 0; i < 65535; i++)
        {
            var c = (char)i;
            if (zalgo.Contains(Char.GetUnicodeCategory(c)))
            {


                File.AppendAllText("IsModifyLike.html", string.Format("<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>A&#{3};&#{3};&#{3}</td></tr>\n",  i.ToString("X"), c, Char.GetUnicodeCategory(c), i));

            }
        }
        File.AppendAllText("IsModifyLike.html", "</table>");
    }

通过查看生成的表,您应该能够看到哪些堆栈。 维基上缺少的一个范围是06D6-06DC另一个0730-0749

<强>更新

Here's updated regex应该消灭所有zalgo,包括在“正常”范围内绕过的zalgo。

([\u0300–\u036F\u1AB0–\u1AFF\u1DC0–\u1DFF\u20D0–\u20FF\uFE20–\uFE2F\u0483-\u0486\u05C7\u0610-\u061A\u0656-\u065F\u0670\u06D6-\u06ED\u0711\u0730-\u073F\u0743-\u074A\u0F18-\u0F19\u0F35\u0F37\u0F72-\u0F73\u0F7A-\u0F81\u0F84\u0e00-\u0eff\uFC5E-\uFC62]{2,})

最难的是识别它们,一旦你做到了 - 有很多解决方案,包括上面的一些好的解决方案。

希望这可以节省你一些时间。