Как предотвратить текст Z͎̠͗ͣḁ̵͙̑l͎̠͗ͣḁ̵͙̑g͔̤̞͓̐̓̒̽o͓̳͇̔ͥ?

Я читал о том, как работает текст Zalgo, и я хочу узнать, как программное обеспечение чата или форума может предотвратить такое раздражение. Точнее говоря, что такое полный набор символов Unicode, который должен:

а) либо быть раздетым, предполагая, что участники чата должны использовать только те языки, которые не требуют комбинированных меток (т.е. вы можете написать "жених" с комбинированной меткой, но вы будете самим Залго, если будете настаивать на этом) так); или же,

б) уменьшено до максимум 8 последовательных символов (максимум встречается в реальных языках)?

РЕДАКТИРОВАТЬ: Тем временем я нашел совершенно другой вопрос (" Как защититься от... диакритики? "), Который по сути такой же, как этот. Я сделал его название более явным, чтобы другие тоже его нашли.

Ответ 1

Предполагая, что вы очень серьезно относитесь к этому и хотите получить техническое решение, которое вы можете сделать следующим образом:

  • Разделить входящий текст на более мелкие единицы (слова или предложения);
  • Отметьте каждую единицу на сервере с выбранным шрифтом (с огромной высотой строки и большим количеством места ниже базовой линии, где будет "шум" Zalgo);
  • Постройте алгоритм машинного обучения, чтобы судить, выглядит ли он слишком "темным" и "занятым";
  • Если доверие к алгоритму низкое, отложите его до модераторов.

Это может быть интересно реализовать, но на практике, вероятно, лучше сразу перейти к шагу 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 of 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.  

Ответ 2

Сделать overflow:hidden коробки overflow:hidden. На самом деле он не отключает текст Zalgo, но предотвращает повреждение других комментариев.

.comment {
  /* the overflow: hidden is what prevents one comment 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>

Ответ 3

Ранее задавался связанный с этим вопрос: https://stackoverflow.com/questions/5073191/how-is-zalgo-text-implemented, но здесь интересно провести профилактику.

С точки зрения предотвращения этого вы можете выбрать несколько стратегий:

  • не допускать объединения диакритических знаков полностью (и сокрушить многих международных пользователей),
  • отфильтровать комбинацию символов с использованием белого списка или черного списка (и сокрушить меньший процент международных пользователей).
  • предотвратить определенное количество комбинированных символов (и мочу даже меньшего процента пользователей)
  • У вас есть здоровое сообщество модераторов (со всеми минусами, которые есть, см. ваш вопрос в качестве примера здесь).

Ответ 4

Вы можете избавиться от текста Zalgo в своем приложении, используя strip-combining-marks от Mathias Bynens.

Модуль 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"

Ответ 5

Используя PHP и мышление работника по сносу, вы можете избавиться от Zalgo с помощью функции iconv. Конечно, это также убьет любые другие символы UTF-8.

$unZalgoText = iconv("UTF-8", "ISO-8859-1//IGNORE", $zalgoText);