Co słychać w tych łączących znaki Unicode i jak możemy je filtrować?

91

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

Ostatnio pojawiły się w sekcjach komentarzy na Facebooku.

Jak możemy to oczyścić?

XCS
źródło
5
Czy nie zadałeś wcześniej tego pytania? (
Szczere
5
To zdecydowanie nie są ascii
Chris Eberle
31
Dlaczego głosy zamykające? To pytanie związane z programowaniem, ponieważ chcę wiedzieć, jak wyczyścić tego typu dane wejściowe, aby sekcje komentarzy na mojej stronie internetowej nie były placem zabaw dla 13-latka ...
XCS
17
กิิิิิิิิิิิิิิิิิิิิ ก้้้้้้้้้้้้้้้้้้้้ ก็็็็็็็็็็็็็็็็็็็็ ก็็็็็็็็็็็็็็็็็็็็ กิิิิิิิิิิิิิิิิิิิิ ก้้้้้้้้้้้้้้้้้้้้ ก็็็็็็็็็็็็็็็็็็็็ กิิิิิิิิิิิิิิิิิิิิ ก้้้้้้้้้้้้้้้้้้้้ กิิิิิิิิิิิิิิิิิิิิ ก้้้้้้้้้้้้้้้้้้้้ ก็็็็็็็็็็็็็็็็็็็็ ก็็็็็็็็็็็็็็็็็็็็ กิิิิิิิิิิิิิิิิิิิิ ก้้้้้้้้้้้้้้้้้้้้ ก็็็็็็็็็็็็็็็็็็็็ กิิิิิิิิิิิิิิิ ", więc sekcje z komentarzami na mojej stronie nie będą placem zabaw dla 13-latka." Właściwie bez oczyszczenia jedno umieszczenie tych znaków może spowodować, że komentarz nad nim stanie się nieczytelny, co wcale nie jest przyjemne dla użytkownika.
XCS
14
@pjotr To na pewno nie jest błąd przeglądarki. Jeśli chcesz, aby znaki nie przepełniły pola zawierającego, możesz po prostu rozwiązać to za pomocą CSS (overflow: hidden;) ...
XCS

Odpowiedzi:

80

O co chodzi z tymi postaciami Unicode?

To postać z serią łączących się postaci . Ponieważ kombinowane znaki, o których mowa, chcą wyjść powyżej znaku podstawowego, nakładają się (dosłownie). Na przykład sprawa

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

... to ก (tajski znak ko kai ) ( U + 0E01 ), po którym następuje 20 kopii tajskiego łączącego znak mai tho ( U + 0E49 ).

Jak możemy to oczyścić?

Państwo mogli wstępnie przetworzyć tekst i ograniczyć liczbę łączących znaków, które można zastosować do pojedynczego znaku, ale wysiłek nie może być warta nagrody. Potrzebowałbyś arkuszy danych dla wszystkich obecnych znaków, aby wiedzieć, czy są one łączone, czy co, i musisz zezwolić na co najmniej kilka, ponieważ niektóre języki są zapisane kilkoma znakami diakrytycznymi na jednej podstawie . Teraz, jeśli chcesz ograniczyć komentarze do zestawu znaków łacińskich, byłoby to łatwiejsze do sprawdzenia zakresu, ale oczywiście jest to tylko opcja, jeśli chcesz ograniczyć komentarze tylko do kilku języków. Więcej informacji, arkusze kodów itp. Na unicode.org .

BTW, jeśli kiedykolwiek chciałbyś wiedzieć, jak została skomponowana jakaś postać, dla innego pytania niedawno zakodowałem szybką i brudną stronę „Unicode Show Me” w JSBin. Po prostu skopiuj i wklej tekst do obszaru tekstowego, a zobaczysz wszystkie punkty kodowe (~ znaki), z których składa się tekst, wraz z linkami, takimi jak te powyżej, do strony opisującej każdy znak. Działa tylko dla punktów kodowych w zakresie U + FFFF i poniżej, ponieważ jest napisane w JavaScript i aby obsłużyć znaki powyżej U + FFFF w JavaScript, musisz wykonać więcej pracy niż chciałem zrobić dla tego pytania (ponieważ w JavaScript, a „znak” jest zawsze 16 bitów, co oznacza, że ​​w niektórych językach znak można podzielić na dwa oddzielne „znaki” JavaScript, czego nie uwzględniłem), ale jest to przydatne w przypadku większości tekstów ...

TJ Crowder
źródło
1
Czy nie usunąłbyś po prostu powtórzonych kopii tego samego łączącego się punktu kodowego z powrotem w jedną kopię? Czy kiedykolwiek musiałbyś łączyć ten sam punkt kodowy w podstawowy punkt kodowy więcej niż raz?
Remy Lebeau
4
@RemyLebeau: "Czy kiedykolwiek potrzebowałbyś połączyć ten sam punkt kodowy w podstawowy punkt kodowy więcej niż raz?" Nie wiem, wiem bardzo, bardzo mało o tym, jak piszesz inne języki - na przykład tajski. Nie zdziwiłbym się wcale, gdybym się dowiedział, że w niektórych przypadkach ważny był więcej niż jeden ten sam punkt kodowy. Ale zrobienie tego nie zmniejsza złożoności; nadal potrzebujesz jednej z tabel Unicode, aby dowiedzieć się, które z nich łączą znaki.
TJ Crowder
Sprawiłem,
ubershmekel
2
Biblioteka JavaScript do łatwego usuwania znaków łączących Unicode z ciągów: mths.be/stripcombiningmarks
Mathias Bynens
JavaScript używa UTF-16 z « parami zastępczymi »
dolmen
17

Jeśli masz silnik wyrażeń regularnych z przyzwoitą obsługą Unicode, czyszczenie tego rodzaju ciągów jest trywialne. Na przykład w Perlu możesz usunąć wszystkie znaki łączenia oprócz pierwszego z każdego znaku (postrzeganego przez użytkownika) w następujący sposób:

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

Spowoduje to wydrukowanie:

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

nwellnhof
źródło
9
Nie umiem czytać po tybetańsku, ale obawiam się, że takie podejście brutalnej siły może usunąć funkcjonalność ze sposobu projektowania języka. Widziałem Unicode, który ma uzasadnione przypadki użycia więcej niż jednego znaku łączącego. Arabski jest dobrym przykładem. Postaram się zapamiętać, aby prowadzić to przez moich tybetańskich współpracowników.
FlipMcF
2
Masz rację, z pewnością są przypadki, w których wielokrotne łączenie znaków jest uzasadnione. Ale możesz łatwo zmienić wyrażenie regularne, aby zezwolić na określoną maksymalną liczbę znaków.
nwellnhof
Uzyskał głos za, ponieważ odpowiada na pytanie „jak to oczyścić”. Ale myślę, że byłby to koszmar konserwacji.
FlipMcF
Ponadto RE po prostu usuwa sąsiednie duplikaty. Nie byłoby posprzątać, powiedzieć: <base><macron><overline><macron><overline>.... Tak więc, jeśli twój tekst wymaga wielu różnych łączących się znaków, przejdzie dobrze; a złośliwy tekst nadal mógłby zostać utworzony.
Jesse Chisholm
13

„Jak możemy to odkażać” najlepiej odpowiada powyżej TJ Crowder

Uważam jednak, że sanityzacja jest złym podejściem i Cristy ma rację z overflow:hiddenelementem zawierającym css.

Przynajmniej tak to rozwiązuję.

FlipMcF
źródło
6

Okej, zajęło mi to trochę czasu, miałem wrażenie, że łączenie znaków w celu wyprodukowania zalgo ogranicza się do tych . Spodziewałem się więc, że podążanie za wyrażeniem regularnym złapie dziwaków.

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

i to nie zadziałało ...

Problem polega na tym, że lista na wiki nie obejmuje pełnego zakresu łączonych postaci.

To, co dało mi wskazówkę, to "ก้้้้้้้้้้้้้้้้้้้้".charCodeAt(2).toString(16)= "e49", które nie będąc w zasięgu łączenia, zalicza się do „użytku prywatnego”.

W C # podlegają one UnicodeCategory.NonSpacingMarki następujący skrypt je opróżnia:

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

Patrząc na wygenerowany stół, powinieneś być w stanie zobaczyć, które z nich układają się w stos. Jeden zakres, którego brakuje na wiki, jest 06D6-06DCinny 0730-0749.

AKTUALIZACJA:

Oto zaktualizowane wyrażenie regularne, które powinno wyłowić wszystkie zalgo, w tym pominięte w „normalnym” zakresie.

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

Najtrudniej jest je zidentyfikować, kiedy już to zrobisz - istnieje wiele rozwiązań, w tym kilka dobrych powyżej.

Mam nadzieję, że zaoszczędzi ci to trochę czasu.

Matas Vaitkevicius
źródło
Powiedziałbym, żeby nie spamować tego spamu!
Praveen Kumar Purushothaman
@PraveenKumar Czy chciałbyś wyjaśnić, co masz na myśli?
Matas Vaitkevicius
Doceniam twoją odpowiedź, ale to jest pytanie bez odpowiedzi. Po co więc niepotrzebnie dodawać nowe odpowiedzi? To tylko mój pogląd. Co więcej, twoja odpowiedź nie brzmi JavaScript, prawda?
Praveen Kumar Purushothaman
4
@PraveenKumar Odkrywa, dlaczego normalna walidacja zalgo ([\u0300–\u036F\u1AB0–\u1AFF\u1DC0–\u1DFF\u20D0–\u20FF\uFE20–\uFE2F]{2,})nie działa. Czy nie jest interesujące, że łączenie Unicode nie ogranicza się do tego, co jest na wiki? Co rozumiesz przez „pytanie z utraconą odpowiedzią”? EDYCJA : Może wydawać się dziwne, aby dodać odpowiedź na pytanie 3-latka, ale ponieważ zajęło mi trochę czasu, zanim zrozumiałem, dlaczego ten rodzaj zalgo działał, nie mogłem pozwolić, aby taka wiedza poszła na marne. Następny facet zaoszczędzi trochę czasu.
Matas Vaitkevicius
7
@PraveenKumar pytanie nie określa języka, a umieszczenie nowej odpowiedzi na stare pytanie jest całkowicie właściwe, jeśli stare odpowiedzi były w jakiś sposób niepełne. Niestety nie mam wystarczającego doświadczenia z tym problemem, inaczej dostałbym ode mnie pozytywną opinię.
Mark Ransom