21

我已经阅读了有关Zalgo 文本的工作原理的信息,并且我希望了解聊天或论坛软件如何防止这种烦恼。更准确地说,完整的 Unicode 组合字符集是什么,需要:

a) 要么被剥夺,假设聊天参与者只使用不需要组合标记的语言(即你可以用组合标记写“未婚夫”,但如果你坚持这样做,你自己会有点 Zalgo'ed所以); 或者,

b) 减少到最多 8 个连续字符(实际语言中遇到的最大值)?

编辑:与此同时,我发现了一个完全不同的措辞问题(“如何防止......变音符号? ”),这与这个问题基本相同。我使它的标题更明确,以便其他人也能找到它。

4

5 回答 5

20

假设您对此非常认真并想要一个技术解决方案,您可以执行以下操作:

  1. 将输入的文本拆分成更小的单元(单词或句子);
  2. 使用您选择的字体渲染服务器上的每个单元(在 Zalgo “噪音”所在的基线下方有很大的行高和大量空间);
  3. 训练一个机器学习算法来判断它是否看起来太“黑暗”和“忙碌”;
  4. 如果算法的置信度较低,请遵照人工审核。

这可能很有趣,但实际上最好直接进入第四步。

编辑:这是 Python 2.7 中更实用但更直接的解决方案。分类为“标记,非间距”“标记,封闭”的Unicode 字符似乎是用于创建 Zalgo 效果的主要工具。与上述想法不同,这不会尝试确定文本的“美学”,而是简单地删除所有此类字符。(不用说,这会破坏许多语言中的文本。请继续阅读以获得更好的解决方案。)要过滤掉更多字符类别,请将它们添加到ZALGO_CHAR_CATEGORIES.

#!/usr/bin/env python
import unicodedata
import codecs

ZALGO_CHAR_CATEGORIES = ['Mn', 'Me']

with codecs.open("zalgo", 'r', 'utf-8') as infile:
    for line in infile:
        print ''.join([c for c in unicodedata.normalize('NFD', line) if unicodedata.category(c) not in ZALGO_CHAR_CATEGORIES]),

示例输入:

1
H̡̫̤ͭ̓̓̇͗̎̀ơ̯̗͒̄̀̈ͤ̀͡w͓̲͙͋ͬ̊ͦ̂̀̚ ͎͉͖̌ͯͅͅd̳̘̿̃̔̏ͣ͂̉̕ŏ̖̙͋ͤ̊͗̓͟͜e͈͕̯̮͌ͭ̍̐̃͒s͙͔̺͇̗̱̿̊̇͞ ̸ͩͩ͑̋̀ͮͥͦ̊Z̆̊͊҉҉̠̱̦̩͕ą̟̹͈̺̹̋̅ͯĺ̡̘̹̻̩̩͋͘g̪͚͗ͬ͒o̢̖͇̬͍͇̔͋͊̓ ̢͈͂ͣ̏̿͐͂ͯ͠t̛͓̖̻̲ͤ̈ͣ͝e͋̄ͬ̽͜҉͚̭͇ͅx̌ͤ̓̂̓͐͐́͋͡ț̗̹̄̌̀ͧͩ̕͢ ̮̗̩̳̱̾w͎̭̤̄͗ͭ̃͗ͮ̐o̢̯̻̾ͣͬ̽̔̍͟r̢̪͙͍̠̀ͅǩ̵̶̗̮̮ͪ́?̙͉̥̬ͤ̌͗ͩ̕͡
2
H̡̫̤ͭ̓̓̇͗̎̀ơ̯̗͒̄̀̈ͤ̀͡w͓̲͙͋ͬ̊ͦ̂̀̚ ͎͉͖̌ͯͅͅd̳̘̿̃̔̏ͣ͂̉̕ŏ̖̙͋ͤ̊͗̓͟͜e͈͕̯̮͌ͭ̍̐̃͒s͙͔̺͇̗̱̿̊̇͞ ̸ͩͩ͑̋̀ͮͥͦ̊Z̆̊͊҉҉̠̱̦̩͕ą̟̹͈̺̹̋̅ͯĺ̡̘̹̻̩̩͋͘g̪͚͗ͬ͒o̢̖͇̬͍͇̔͋͊̓ ̢͈͂ͣ̏̿͐͂ͯ͠t̛͓̖̻̲ͤ̈ͣ͝e͋̄ͬ̽͜҉͚̭͇ͅx̌ͤ̓̂̓͐͐́͋͡ț̗̹̄̌̀ͧͩ̕͢ ̮̗̩̳̱̾w͎̭̤̄͗ͭ̃͗ͮ̐o̢̯̻̾ͣͬ̽̔̍͟r̢̪͙͍̠̀ͅǩ̵̶̗̮̮ͪ́?̙͉̥̬ͤ̌͗ͩ̕͡
3

输出:

1
How does Zalgo text work?
2
How does Zalgo text work?
3

最后,如果您希望检测而不是无条件删除 Zalgo 文本,您可以执行字符频率分析。下面的程序对输入文件的每一行执行此操作。该函数is_zalgo为给定字符串的每个单词计算一个“Zalgo 分数”(分数是潜在的 Zalgo 字符数除以字符总数)。然后查看单词分数的第三个四分位数是否大于THRESHOLD。如果THRESHOLD等于0.5,则意味着我们正在尝试检测每四个单词中的一个是否有超过 50% 的 Zalgo 字符。(THRESHOLD猜测为 0.5,可能需要针对实际使用进行调整。)就收益/编码工作而言,这种类型的算法可能是最好的。

#!/usr/bin/env python
from __future__ import division
import unicodedata
import codecs
import numpy

ZALGO_CHAR_CATEGORIES = ['Mn', 'Me']
THRESHOLD = 0.5
DEBUG = True

def is_zalgo(s):
    if len(s) == 0:
        return False
    word_scores = []
    for word in s.split():
        cats = [unicodedata.category(c) for c in word]
        score = sum([cats.count(banned) for banned in ZALGO_CHAR_CATEGORIES]) / len(word)
        word_scores.append(score)
    total_score = numpy.percentile(word_scores, 75)
    if DEBUG:
        print total_score
    return total_score > THRESHOLD

with codecs.open("zalgo", 'r', 'utf-8') as infile:
    for line in infile:
        print is_zalgo(unicodedata.normalize('NFD', line)), "\t", line

样本输出:

0.911483990148
True    Señor, could you or your fiancé explain, H̡̫̤ͭ̓̓̇͗̎̀ơ̯̗͒̄̀̈ͤ̀͡w͓̲͙͋ͬ̊ͦ̂̀̚ ͎͉͖̌ͯͅͅd̳̘̿̃̔̏ͣ͂̉̕ŏ̖̙͋ͤ̊͗̓͟͜e͈͕̯̮͌ͭ̍̐̃͒s͙͔̺͇̗̱̿̊̇͞ ̸ͩͩ͑̋̀ͮͥͦ̊Z̆̊͊҉҉̠̱̦̩͕ą̟̹͈̺̹̋̅ͯĺ̡̘̹̻̩̩͋͘g̪͚͗ͬ͒o̢̖͇̬͍͇̔͋͊̓ ̢͈͂ͣ̏̿͐͂ͯ͠t̛͓̖̻̲ͤ̈ͣ͝e͋̄ͬ̽͜҉͚̭͇ͅx̌ͤ̓̂̓͐͐́͋͡ț̗̹̄̌̀ͧͩ̕͢ ̮̗̩̳̱̾w͎̭̤̄͗ͭ̃͗ͮ̐o̢̯̻̾ͣͬ̽̔̍͟r̢̪͙͍̠̀ͅǩ̵̶̗̮̮ͪ́?̙͉̥̬ͤ̌͗ͩ̕͡

0.333333333333
False   Příliš žluťoučký kůň úpěl ďábelské ódy.  
于 2014-03-09T08:49:06.560 回答
12

制作盒子overflow:hidden。它实际上并没有禁用 Zalgo 文本,但它可以防止它破坏其他评论。

.comment {
  /* the overflow: hidden is what prevents one comment's combining marks from affecting its siblings */
  overflow: hidden;
  /* the padding gives space for any legitimate combining marks */
  padding: 0.5em;
  /* the rest are just to visually divide the three comments */
  border: solid 1px #ccc;
  margin-top: -1px;
  margin-bottom: -1px;
}
<div class=comment>The below comment looks awful.</div>
<div class=comment>H̡̫̤ͭ̓̓̇͗̎̀ơ̯̗͒̄̀̈ͤ̀͡w͓̲͙͋ͬ̊ͦ̂̀̚ ͎͉͖̌ͯͅͅd̳̘̿̃̔̏ͣ͂̉̕ŏ̖̙͋ͤ̊͗̓͟͜e͈͕̯̮͌ͭ̍̐̃͒s͙͔̺͇̗̱̿̊̇͞ ̸ͩͩ͑̋̀ͮͥͦ̊Z̆̊͊҉҉̠̱̦̩͕ą̟̹͈̺̹̋̅ͯĺ̡̘̹̻̩̩͋͘g̪͚͗ͬ͒o̢̖͇̬͍͇̔͋͊̓ ̢͈͂ͣ̏̿͐͂ͯ͠t̛͓̖̻̲ͤ̈ͣ͝e͋̄ͬ̽͜҉͚̭͇ͅx̌ͤ̓̂̓͐͐́͋͡ț̗̹̄̌̀ͧͩ̕͢ ̮̗̩̳̱̾w͎̭̤̄͗ͭ̃͗ͮ̐o̢̯̻̾ͣͬ̽̔̍͟r̢̪͙͍̠̀ͅǩ̵̶̗̮̮ͪ́?̙͉̥̬ͤ̌͗ͩ̕͡</div>
<div class=comment>The above comment looks awful.</div>

于 2017-04-07T20:10:05.410 回答
6

之前提出了一个相关问题:https ://stackoverflow.com/questions/5073191/how-is-zalgo-text-implemented但在这里进行预防很有趣。

为了防止这种情况,您可以选择几种策略:

  1. 防止完全组合变音符号(并激怒许多国际用户),
  2. 使用白名单或黑名单过滤掉组合字符(并激怒一小部分国际用户)
  3. 防止一定数量的组合字符(以及更小比例的用户小便)
  4. 拥有一个健康的版主社区(具有所有缺点,请在此处以您的问题为例)
于 2014-03-09T08:24:37.577 回答
4

您可以使用 Mathias Bynens的 strip-combining-marks摆脱应用程序中的 Zalgo 文本。

模块strip-combining-marks可用于浏览器(通过 Bower)和 Node.js 应用程序(通过 npm)。

这是一个关于如何将它与 npm 一起使用的示例:

var stripCombiningMarks = require("strip-combining-marks");
var zalgoText = 'U̼̥̻̮͍͖n͠i͏c̯̮o̬̝̠͉̤d͖͟e̫̟̗͟ͅ';
var stripptedText = stripCombiningMarks(zalgoText); // "Unicode"
于 2017-03-14T16:14:22.950 回答
2

使用 PHP 和拆迁工人的思维方式,您可以通过 iconv 函数摆脱 Zalgo。当然,这也会杀死任何其他 UTF-8 字符。

$unZalgoText = iconv("UTF-8", "ISO-8859-1//IGNORE", $zalgoText);
于 2018-02-13T19:21:36.287 回答