O que há com esses caracteres de combinação Unicode e como podemos filtrá-los?

91

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

Recentemente, eles apareceram nas seções de comentários do Facebook.

Como podemos higienizar isso?

XCS
fonte
5
Você não fez essa pergunta antes? (Pergunta honesta.)
Ry-
5
Esses definitivamente não são ascii
Chris Eberle
31
Por que os votos finais? É uma questão de programação, pois quero saber como higienizar esse tipo de entrada para que as seções de comentários do meu site não sejam o playground dos 13 anos ...
XCS
17
กิิิิิิิิิิิิิิิิิิิิ ก้้้้้้้้้้้้้้้้้้้้ ก็็็็็็็็็็็็็็็็็็็็ ก็็็็็็็็็็็็็็็็็็็็ กิิิิิิิิิิิิิิิิิิิิ ก้้้้้้้้้้้้้้้้้้้้ ก็็็็็็็็็็็็็็็็็็็็ กิิิิิิิิิิิิิิิิิิิิ ก้้้้้้้้้้้้้้้้้้้้ กิิิิิิิิิิิิิิิิิิิิ ก้้้้้้้้้้้้้้้้้้้้ ก็็็็็็็็็็็็็็็็็็็็ ก็็็็็็็็็็็็็็็็็็็็ กิิิิิิิิิิิิิิิิิิิิ ก้้้้้้้้้้้้้้้้้้้้ ก็็็็็็็็็็็็็็็็็็็็ กิิิิิิิิิิิิิิิ "então as seções de comentários no meu site não serão o playground dos 13 anos." Na verdade, sem a limpeza, postar esses caracteres pode tornar o comentário acima dele ilegível, o que não é uma experiência de usuário agradável.
XCS
14
@pjotr Definitivamente não é um bug do navegador. Se você quiser que os caracteres não excedam a caixa que contém, você pode simplesmente resolver isso com CSS (overflow: hidden;) ...
XCS

Respostas:

80

O que há com esses personagens Unicode?

É um personagem com uma série de personagens combinados . Como os caracteres combinados em questão querem ir acima do caractere base, eles se acumulam (literalmente). Por exemplo, o caso de

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

... é um ก (caractere tailandês ko kai ) ( U + 0E01 ) seguido por 20 cópias do caractere combinatório tailandês mai tho ( U + 0E49 ).

Como podemos higienizar isso?

Você pode pré-processar o texto e limitar o número de caracteres combinados que podem ser aplicados a um único personagem, mas o esforço pode não valer a recompensa. Você precisaria das folhas de dados de todos os caracteres atuais para saber se eles estavam se combinando ou o quê, e você precisaria ter certeza de permitir pelo menos alguns porque alguns idiomas são escritos com vários diacríticos em uma única base . Agora, se você quiser limitar os comentários ao conjunto de caracteres latinos, seria uma verificação de intervalo mais fácil, mas é claro que é apenas uma opção se você quiser limitar os comentários a apenas alguns idiomas. Mais informações, planilhas de código, etc. em unicode.org .

Aliás, se você quiser saber como algum personagem foi composto, para outra pergunta recentemente eu codifiquei uma página "Unicode Show Me" rápida e suja no JSBin. Você apenas copia e cola o texto na área de texto, e ele mostra todos os pontos de código (~ caracteres) dos quais o texto é composto, com links como os acima para a página que descreve cada caractere. Ele só funciona para pontos de código no intervalo U + FFFF e abaixo, porque é escrito em JavaScript e para lidar com caracteres acima de U + FFFF em JavaScript, você tem que fazer mais trabalho do que eu queria para essa questão (porque em JavaScript, um "personagem" é sempre 16 bits, o que significa que para alguns idiomas um caractere pode ser dividido em dois "caracteres" JavaScript separados e eu não levei em consideração isso), mas é útil para a maioria dos textos ...

TJ Crowder
fonte
1
Você não iria simplesmente deletar cópias repetidas do mesmo ponto de código de combinação em uma única cópia? Quando você precisaria combinar o mesmo ponto de código em um ponto de código base mais de uma vez?
Remy Lebeau
4
@RemyLebeau: "Quando você precisaria combinar o mesmo ponto de código em um ponto de código base mais de uma vez?" Não sei, sei muito, muito pouco sobre como você escreve em outras línguas - tailandês, por exemplo. Eu não ficaria surpreso em descobrir que mais de um ponto de código igual era válido em alguns. Mas fazer isso não reduz a complexidade; você ainda precisa de uma das tabelas Unicode para descobrir quais estão combinando caracteres.
TJ Crowder
Fiz sua página aceitar a string Unicode do url, por exemplo, jsbin.com/erajer/7/…
ubershmekel
2
Biblioteca JavaScript para remover facilmente as marcas de combinação Unicode de strings: mths.be/stripcombiningmarks
Mathias Bynens
JavaScript usa UTF-16 com « pares substitutos »
dolmen
17

Se você tiver um mecanismo regex com suporte decente a Unicode, é trivial limpar esse tipo de string. Em Perl, por exemplo, você pode remover tudo, exceto a primeira marca de combinação de cada caractere (percebido pelo usuário) como este:

#!/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");

Isso irá imprimir:

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

Nwellnhof
fonte
9
Não consigo ler tibetano, mas estou preocupado que essa abordagem de força bruta possa remover a funcionalidade da maneira como a linguagem é projetada. Eu vi Unicode que tem casos de uso legítimos de mais de uma marca de combinação. O árabe é um bom exemplo. Vou tentar me lembrar de fazer isso por meus colegas tibetanos.
FlipMcF
2
Você está certo, certamente há casos em que várias marcas de combinação são legítimas. Mas você pode alterar facilmente o regex para permitir um determinado máximo de marcas.
nwellnhof de
Ele foi votado positivamente porque responde à pergunta 'como limpar isso'. Mas acho que isso seria um pesadelo de manutenção.
FlipMcF
Além disso, a ER apenas remove a duplicação adjacente . Não seria limpar, dizem: <base><macron><overline><macron><overline>.... Portanto, se o seu texto precisa de vários caracteres de combinação diferentes , ele passará bem; e o texto malicioso ainda pode ser criado.
Jesse Chisholm
13

"Como podemos higienizar isso" é melhor respondido acima por TJ Crowder

No entanto, acho que a higienização é a abordagem errada, e Cristy acertou overflow:hiddenno elemento que contém o css.

Pelo menos, é assim que estou resolvendo.

FlipMcF
fonte
6

Ok, este me levou um tempo para descobrir, eu estava com a impressão de que combinar personagens para produzir zalgo se limita a eles . Então eu esperava que seguir o regex pegasse os malucos.

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

e não funcionou ...

O problema é que a lista no wiki não cobre uma gama completa de caracteres combinados.

O que me deu uma dica é "ก้้้้้้้้้้้้้้้้้้้้".charCodeAt(2).toString(16)= "e49", que não está dentro de uma faixa de combinação, cai em 'Uso privado'.

Em C # eles se enquadram UnicodeCategory.NonSpacingMarke o seguinte script os elimina:

    [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>");
    }

Observando a tabela gerada, você poderá ver quais são empilhadas. Um intervalo que está faltando no wiki é 06D6-06DCoutro 0730-0749.

ATUALIZAR:

Aqui está o regex atualizado que deve pescar todos os zalgo, incluindo aqueles contornados na faixa 'normal'.

([\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,})

A parte mais difícil é identificá-los, uma vez que você tenha feito isso - há uma infinidade de soluções, incluindo algumas boas acima.

Espero que isso economize algum tempo.

Matas Vaitkevicius
fonte
Eu diria, para não enviar spam para esse spam!
Praveen Kumar Purushothaman
@PraveenKumar Você se importaria de explicar o que você quis dizer?
Matas Vaitkevicius
Agradeço sua resposta, mas esta é uma pergunta perdida. Então, por que adicionar novas respostas desnecessariamente? É apenas minha opinião. Além disso, sua resposta não é JavaScript, certo?
Praveen Kumar Purushothaman
4
@PraveenKumar Ele descobre por que a validação normal do zalgo ([\u0300–\u036F\u1AB0–\u1AFF\u1DC0–\u1DFF\u20D0–\u20FF\uFE20–\uFE2F]{2,})não funciona. Você não acha interessante que empilhar Unicode não se limita ao que está no wiki? O que você quer dizer com 'pergunta perdida respondida'? EDIT : Você pode achar estranho adicionar uma resposta a uma pergunta de 3 anos, mas como demorei um pouco para descobrir por que esse tipo de zalgo funcionava, não poderia deixar esse conhecimento desperdiçar. O próximo cara vai economizar tempo.
Matas Vaitkevicius
7
@PraveenKumar a pergunta não indica um idioma, e postar uma nova resposta em uma pergunta antiga é totalmente apropriado se as respostas antigas forem deficientes de alguma forma. Infelizmente, não tenho experiência suficiente com esse problema, ou ele teria um voto positivo de mim.
Mark Ransom