Warum vermeidet modernes Perl standardmäßig UTF-8?

557

Ich frage mich, warum die meisten modernen Lösungen, die mit Perl erstellt wurden, UTF-8 nicht standardmäßig aktivieren.

Ich verstehe, dass es viele ältere Probleme für Perl-Kernskripte gibt, bei denen es zu Problemen kommen kann. Aber aus meiner Sicht, in dem 21 st Jahrhundert große neue Projekte (oder Projekte mit einer großen Perspektive) sollten ihre Software UTF-8 Nachweis von Grunde auf neu machen. Ich sehe es immer noch nicht. Zum Beispiel aktiviert Moose strenge Warnungen und Warnungen, nicht jedoch Unicode . Modern :: Perl reduziert auch die Boilerplate, aber keine UTF-8-Handhabung.

Warum? Gibt es einige Gründe, UTF-8 in modernen Perl-Projekten im Jahr 2011 zu vermeiden?


Das Kommentieren von @tchrist wurde zu lang, daher füge ich es hier hinzu.

Es scheint, dass ich mich nicht klar ausgedrückt habe. Lassen Sie mich versuchen, einige Dinge hinzuzufügen.

tchrist und ich sehen die Situation ziemlich ähnlich, aber unsere Schlussfolgerungen sind völlig gegensätzlich. Ich stimme zu, die Situation mit Unicode ist kompliziert, aber aus diesem Grund benötigen wir (Perl-Benutzer und -Codierer) eine Ebene (oder ein Pragma), die die Handhabung von UTF-8 so einfach macht, wie es heutzutage sein muss.

tchrist wies auf viele Aspekte hin, die behandelt werden müssen. Ich werde sie tagelang oder sogar wochenlang lesen und darüber nachdenken. Trotzdem ist das nicht mein Punkt. tchrist versucht zu beweisen, dass es keinen einzigen Weg gibt, "UTF-8 zu aktivieren". Ich habe nicht so viel Wissen, um damit zu streiten. Also bleibe ich bei lebenden Beispielen.

Ich habe mit Rakudo herumgespielt und UTF-8 war genau dort , wo ich es brauchte . Ich hatte keine Probleme, es hat einfach funktioniert. Vielleicht gibt es irgendwo tiefer einige Einschränkungen, aber am Anfang hat alles, was ich getestet habe, wie erwartet funktioniert.

Sollte das nicht auch im modernen Perl 5 ein Ziel sein? Ich betone es mehr: Ich schlage UTF-8 nicht als Standardzeichensatz für Core Perl vor, sondern die Möglichkeit, es mit einem Snap für diejenigen auszulösen , die neue Projekte entwickeln.

Ein weiteres Beispiel, aber mit einem negativeren Ton. Frameworks sollen die Entwicklung erleichtern. Vor einigen Jahren habe ich Web-Frameworks ausprobiert, sie aber einfach weggeworfen, weil das "Aktivieren von UTF-8" so dunkel war. Ich habe nicht gefunden, wie und wo ich die Unicode-Unterstützung einbinden soll. Es war so zeitaufwändig, dass ich es leichter fand, den alten Weg zu gehen. Jetzt sah ich hier, dass es eine Prämie gab, um das gleiche Problem mit Mason 2 zu lösen : Wie kann man Mason2 UTF-8 sauber machen? . Es ist also ein ziemlich neues Framework, aber die Verwendung mit UTF-8 erfordert fundierte Kenntnisse der Interna. Es ist wie ein großes rotes Schild: STOP, benutze mich nicht!

Ich mag Perl wirklich. Der Umgang mit Unicode ist jedoch schmerzhaft. Ich renne immer noch gegen Wände. In gewisser Weise ist tchrist richtig und beantwortet meine Fragen: Neue Projekte ziehen UTF-8 nicht an, weil es in Perl 5 zu kompliziert ist.

wk
quelle
15
Es tut mir leid, aber ich stimme @tchrist zu - UTF-8 ist extrem schwer. Es gibt kein Framework oder Tool, das nur einen Schalter umlegt und dann richtig damit umgeht. Es ist etwas, woran Sie beim Entwerfen Ihrer Anwendung direkt denken müssen - nicht etwas, das ein Framework oder eine Sprache für Sie handhaben kann. Wenn Rakudo zufällig für Sie gearbeitet hat, waren Sie mit Ihren Testfällen nicht abenteuerlustig genug - da es dann einige der Beispiele in @ tchrists Antwort und Metzger geben wird.
Billy ONeal
12
Was genau hoffen Sie von Moose oder Modern :: Perl? Zufällig codierte Zeichendaten in Dateien und Datenbanken auf magische Weise wieder in gültige Daten verwandeln?
Jrockway
13
Was bedeutet das? Elch hat nichts mit Textmanipulation zu tun. Warum sollte es über die Zeichenkodierung Bescheid wissen und noch weniger eine Standardcodierung für Sie auswählen? (Der Grund, warum die von Ihnen aufgelisteten Pragmas die Codierung nicht berühren, liegt darin, dass Perl-Pragmas das lexikalische Verhalten beeinflussen. Angenommen, die gesamte Welt, einschließlich anderer Module, ist UTF-8, ist einfach das Falsche Dies ist hier nicht PHP oder Ruby.)
Jrockway
8
(Auch ... "die meisten modernen Perl-Apps" brechen auf UTF-8? Ich habe sicherlich noch nie eine Anwendung geschrieben, Perl oder sonst, das ist nicht Unicode-sauber.)
Jrockway
11
Nb. tchrist (Tom Christiansen) hat seine [ training.perl.com/OSCON2011/index.html Tom Christiansens Materialien für OSCON 2011] über Unicode veröffentlicht. Der Titel "Unicode Support Shootout: Das Gute, das Schlechte und das (meistens) Hässliche" spricht über die Unicode-Unterstützung in verschiedenen Programmiersprachen. Nur Google Go und Perl5 unterstützen vollständigen Unicode, nur Google Go (keine Erwähnung von Perl6).
Jakub Narębski

Antworten:

1146

𝙎𝙞𝙢𝙥𝙡𝙚𝙨𝙩 : 𝟕 𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚 𝙍𝙚𝙘𝙤𝙢𝙢𝙚𝙣𝙙𝙖𝙩𝙞𝙤𝙣𝙨

  1. PERL_UNICODEStellen Sie Ihre Variable auf ein AS. Dadurch werden alle Perl-Skripte @ARGVals UTF-8-Zeichenfolgen dekodiert und die Codierung aller drei von stdin, stdout und stderr auf UTF-8 gesetzt. Beides sind globale Effekte, keine lexikalischen.

  2. doStellen Sie oben in Ihrer Quelldatei (Programm, Modul, Bibliothek, Hickey) deutlich, dass Sie Perl Version 5.12 oder besser ausführen, über:

    use v5.12;  # minimal for unicode string feature
    use v5.14;  # optimal for unicode string feature
  3. Aktivieren Sie Warnungen, da die vorherige Deklaration nur Einschränkungen und Funktionen aktiviert, keine Warnungen. Ich schlage auch vor, Unicode-Warnungen in Ausnahmen umzuwandeln. Verwenden Sie daher beide Zeilen, nicht nur eine. Beachten Sie jedoch , dass unter v5.14, die utf8umfasst Warnung Klasse drei weitere subwarnings , die alle separat aktiviert werden: nonchar, surrogate, und non_unicode. Diese möchten Sie möglicherweise besser kontrollieren.

    use warnings;
    use warnings qw( FATAL utf8 );
  4. Deklarieren Sie, dass diese Quelleneinheit als UTF-8 codiert ist. Obwohl dieses Pragma einst andere Dinge tat, dient es jetzt nur diesem einen und keinem anderen Zweck:

    use utf8;
  5. Erklären Sie, dass alles, was ein Dateihandle innerhalb dieses lexikalischen Bereichs öffnet, jedoch nicht anderswo , davon ausgeht , dass dieser Stream in UTF-8 codiert ist, sofern Sie nichts anderes angeben. Auf diese Weise wirken Sie sich nicht auf den Code anderer Module oder anderer Programme aus.

    use open qw( :encoding(UTF-8) :std );
  6. Aktivieren Sie benannte Zeichen über \N{CHARNAME}.

    use charnames qw( :full :short );
  7. Wenn Sie ein DATAHandle haben, müssen Sie dessen Codierung explizit festlegen. Wenn Sie möchten, dass dies UTF-8 ist, sagen Sie:

    binmode(DATA, ":encoding(UTF-8)");

Es gibt natürlich kein Ende anderer Angelegenheiten, mit denen Sie sich möglicherweise irgendwann befassen, aber diese werden ausreichen, um das staatliche Ziel zu erreichen, „alles nur mit UTF-8 zum Laufen zu bringen“, wenn auch für einen etwas geschwächten Sinn dieser Begriffe.

Ein anderes Pragma, obwohl es nicht mit Unicode zusammenhängt, ist:

      use autodie;

Es wird dringend empfohlen.

🌴 🐪🐫🐪 🌞 𝕲𝖔 𝕿𝖍𝖔𝖚 𝖆𝖓𝖉 𝕯𝖔 𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊 🌞 🐪🐫🐪 🐪🐫🐪


🎁 🐪 𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊 𝖋𝖔𝖗 𝖀𝖓𝖎𝖈𝖔𝖉𝖊⸗𝕬𝖜𝖆𝖗𝖊 𝕮𝖔𝖉𝖊 𝕮𝖔𝖉𝖊 🐪


Mein eigenes Boilerplate sieht heutzutage so aus:

use 5.014;

use utf8;
use strict;
use autodie;
use warnings; 
use warnings    qw< FATAL  utf8     >;
use open        qw< :std  :utf8     >;
use charnames   qw< :full >;
use feature     qw< unicode_strings >;

use File::Basename      qw< basename >;
use Carp                qw< carp croak confess cluck >;
use Encode              qw< encode decode >;
use Unicode::Normalize  qw< NFD NFC >;

END { close STDOUT }

if (grep /\P{ASCII}/ => @ARGV) { 
   @ARGV = map { decode("UTF-8", $_) } @ARGV;
}

$0 = basename($0);  # shorter messages
$| = 1;

binmode(DATA, ":utf8");

# give a full stack dump on any untrapped exceptions
local $SIG{__DIE__} = sub {
    confess "Uncaught exception: @_" unless $^S;
};

# now promote run-time warnings into stack-dumped
#   exceptions *unless* we're in an try block, in
#   which case just cluck the stack dump instead
local $SIG{__WARN__} = sub {
    if ($^S) { cluck   "Trapped warning: @_" } 
    else     { confess "Deadly warning: @_"  }
};

while (<>)  {
    chomp;
    $_ = NFD($_);
    ...
} continue {
    say NFC($_);
}

__END__

🎅 𝕹 𝖔 𝕸 𝖆 𝖌 𝖎 𝖈 𝕭 𝖚 𝖑 𝖑 𝖑 𝖊 𝖙 🎅


Zu sagen, dass „Perl [ irgendwie! ] Unicode standardmäßig aktivieren “beginnt nicht einmal darüber nachzudenken, genug zu sagen, um in einem seltenen und isolierten Fall auch nur geringfügig nützlich zu sein. Unicode ist viel mehr als nur ein größeres Charakterrepertoire. Es ist auch so, wie diese Charaktere auf viele, viele Arten interagieren.

Selbst die einfältigen Minimalmaßnahmen, von denen (einige) zu glauben scheinen, dass sie sie wollen, brechen garantiert kläglich Millionen von Codezeilen, Code, der keine Chance hat, auf Ihre schicke neue Brave New World zu „upgraden“ Moderne .

Es ist viel, viel komplizierter, als die Leute vorgeben. Ich habe in den letzten Jahren viel darüber nachgedacht. Mir würde gerne gezeigt werden, dass ich falsch liege. Aber ich glaube nicht, dass ich es bin. Unicode ist grundlegend komplexer als das Modell, das Sie ihm auferlegen möchten, und hier gibt es Komplexität, die Sie niemals unter den Teppich kehren können. Wenn Sie es versuchen, brechen Sie entweder Ihren eigenen Code oder den eines anderen. Irgendwann muss man einfach zusammenbrechen und lernen, worum es bei Unicode geht. Sie können nicht so tun, als wäre es etwas, was es nicht ist.

🐪 tut alles, um Unicode einfach zu machen, weit mehr als alles andere, was ich jemals benutzt habe. Wenn Sie der Meinung sind, dass dies schlecht ist, probieren Sie für eine Weile etwas anderes aus. Kehren Sie dann zu 🐪 zurück: Entweder sind Sie in eine bessere Welt zurückgekehrt, oder Sie bringen Wissen darüber mit, damit wir Ihr neues Wissen nutzen können, um things in diesen Dingen besser zu machen.


💡 𝕴𝖉𝖊𝖆𝖘 𝖋𝖔𝖗 𝖆 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 ⸗ 𝕬𝖜𝖆𝖗𝖊 🐪 𝕷𝖆𝖚𝖓𝖉𝖗𝖞 𝕷𝖆𝖚𝖓𝖉𝖗𝖞 💡


Zumindest sind hier einige Dinge erforderlich, damit 🐪 "Unicode standardmäßig aktivieren" kann, wie Sie es ausdrücken:

  1. Der gesamte 🐪 Quellcode sollte standardmäßig in UTF-8 sein. Sie können das mit use utf8oder bekommen export PERL5OPTS=-Mutf8.

  2. Das 🐪- DATAHandle sollte UTF-8 sein. Sie müssen dies pro Paket tun, wie in binmode(DATA, ":encoding(UTF-8)").

  3. Programmargumente für 🐪-Skripte sollten standardmäßig als UTF-8 verstanden werden. export PERL_UNICODE=Aoder perl -CAoder export PERL5OPTS=-CA.

  4. Die Standardeingabe-, Ausgabe- und Fehlerströme sollten standardmäßig UTF-8 sein. export PERL_UNICODE=Sfür alle, oder I, Ound / oder Efür einige von ihnen. Das ist wie perl -CS.

  5. Alle anderen von 🐪 geöffneten Handles sollten als UTF-8 betrachtet werden, sofern nicht anders angegeben. export PERL_UNICODE=Doder mit iund ofür bestimmte von diesen; export PERL5OPTS=-CDwürde funktionieren. Das macht -CSADfür alle.

  6. Decken Sie beide Basen sowie alle Streams ab, mit denen Sie öffnen export PERL5OPTS=-Mopen=:utf8,:std. Siehe Uniquote .

  7. Sie möchten keine UTF-8-Codierungsfehler verpassen. Versuchen Sie es export PERL5OPTS=-Mwarnings=FATAL,utf8. Und stellen Sie sicher, dass Ihre Eingabestreams immer binmoded to sind :encoding(UTF-8), nicht nur to :utf8.

  8. Codepunkte zwischen 128 und 255 sollten unter 🐪 als die entsprechenden Unicode-Codepunkte verstanden werden, nicht nur als nicht propertierte Binärwerte. use feature "unicode_strings"oder export PERL5OPTS=-Mfeature=unicode_strings. Das wird machen uc("\xDF") eq "SS"und "\xE9" =~ /\w/. Ein einfacher export PERL5OPTS=-Mv5.12oder besserer wird das auch bekommen.

  9. Benannte Unicode-Zeichen sind nicht standardmäßig aktiviert. Fügen Sie also export PERL5OPTS=-Mcharnames=:full,:short,latin,greekeinige hinzu. Siehe uninames und tcgrep .

  10. Sie fast immer aus Zugriff auf die Funktionen benötigen die Standard - Unicode::NormalizeModul verschiedene Arten von Zersetzungen. export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKDFühren Sie dann immer eingehende Daten über NFD und ausgehende Daten von NFC aus. Es gibt noch keine E / A-Ebene für diese, die mir bekannt ist, aber siehe nfc , nfd , nfkd und nfkc .

  11. String - Vergleiche in 🐪 mit eq, ne, lc, cmp, sort, und c & cc sind immer falsch. Also statt @a = sort @bdu brauchst @a = Unicode::Collate->new->sort(@b). Könnte das auch zu deinem hinzufügen export PERL5OPTS=-MUnicode::Collate. Sie können den Schlüssel für binäre Vergleiche zwischenspeichern.

  12. 🐪 Integrierte mögen printfund writemachen das Falsche mit Unicode-Daten. Sie müssen das Unicode::GCStringModul für das erstere verwenden, und sowohl das als auch das Unicode::LineBreakModul für das letztere. Siehe uwc und unifmt .

  13. Wenn Sie möchten, dass sie als Ganzzahlen gelten, müssen Sie Ihre \d+Captures durch die Unicode::UCD::numFunktion ausführen, da das integrierte Atoi (3) von currently derzeit nicht clever genug ist.

  14. Auf 👽 Dateisystemen treten Probleme mit dem Dateisystem auf. Einige Dateisysteme erzwingen stillschweigend eine Konvertierung in NFC. andere erzwingen stillschweigend eine Konvertierung in NFD. Und andere machen noch etwas anderes. Einige ignorieren die Angelegenheit sogar ganz, was zu noch größeren Problemen führt. Sie müssen also Ihre eigene NFC / NFD-Behandlung durchführen, um gesund zu bleiben.

  15. Alle Ihre 🐪 Code beteiligt a-zoder A-Zund so muss geändert werden , einschließlich m//, s///und tr///. Es sollte als schreiende rote Fahne hervorstechen, dass Ihr Code kaputt ist. Es ist aber nicht klar, wie es sich ändern muss. Es ist schwieriger, die richtigen Eigenschaften zu finden und ihre Fallfalten zu verstehen, als Sie vielleicht denken. Ich benutze jeden Tag Unichars und Uniprops .

  16. Code, der verwendet \p{Lu}wird , ist fast so falsch wie Code, der verwendet wird [A-Za-z]. Sie müssen \p{Upper}stattdessen verwenden und den Grund dafür kennen. Ja \p{Lowercase}und \p{Lower}unterscheiden sich von \p{Ll}und \p{Lowercase_Letter}.

  17. Code, der verwendet, [a-zA-Z]ist noch schlimmer. Und es kann nicht verwenden \pLoder \p{Letter}; es muss verwenden \p{Alphabetic}. Nicht alle Alphabete sind Buchstaben, wissen Sie!

  18. Wenn Sie nach 🐪 Variablen mit suchen /[\$\@\%]\w+/, haben Sie ein Problem. Sie müssen suchen /[\$\@\%]\p{IDS}\p{IDC}*/, und selbst das denkt nicht an die Interpunktionsvariablen oder Paketvariablen.

  19. Wenn Sie nach Leerzeichen suchen, sollten Sie je nach zwischen \hund wählen \v. Und Sie sollten niemals verwenden \s, da es entgegen der landläufigen Meinung NICHT BEDEUTET [\h\v] .

  20. Wenn Sie \nfür eine Liniengrenze oder sogar verwenden \r\n, dann machen Sie es falsch. Sie müssen verwenden \R, was nicht das gleiche ist!

  21. Wenn Sie nicht wissen, wann und ob Sie Unicode :: Stringprep aufrufen sollen , sollten Sie dies besser lernen.

  22. Vergleiche, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird, müssen prüfen, ob zwei Dinge unabhängig von ihren Diakritika und dergleichen dieselben Buchstaben sind. Der einfachste Weg, dies zu tun, ist mit dem Standardmodul Unicode :: Collate . Unicode::Collate->new(level => 1)->cmp($a, $b). Es gibt auch eqMethoden und dergleichen, und Sie sollten wahrscheinlich auch etwas über die matchund substrMethoden lernen . Diese haben gegenüber den 🐪-Einbauten deutliche Vorteile.

  23. Manchmal reicht das immer noch nicht aus, und Sie benötigen stattdessen das Modul Unicode :: Collate :: Locale wie in Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b). Betrachten Sie das Unicode::Collate::->new(level => 1)->eq("d", "ð")als wahr, aber Unicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð")als falsch. In ähnlicher Weise sind "ae" und "æ", eqwenn Sie keine Gebietsschemas verwenden oder wenn Sie das englische verwenden, sie unterscheiden sich jedoch im isländischen Gebietsschema. Was jetzt? Es ist hart, sage ich dir. Sie können mit ucsort spielen , um einige dieser Dinge zu testen.

  24. Überlegen Sie, wie Sie das Muster CVCV (Konsonsant, Vokal, Konsonant, Vokal) in der Zeichenfolge „ niño “ abgleichen können . Die NFD-Form, an die Sie sich verdammt noch mal besser erinnert haben, wird zu „nin \ x {303} o“. Was wirst du jetzt tun? Selbst wenn Sie so tun, als wäre ein Vokal [aeiou](was übrigens falsch ist), können Sie so etwas auch nicht tun (?=[aeiou])\X), denn selbst in NFD zerfällt ein Codepunkt wie 'ø' nicht ! Mit dem UCA-Vergleich, den ich Ihnen gerade gezeigt habe, wird es jedoch gleich einem 'o' getestet. Sie können sich nicht auf NFD verlassen, Sie müssen sich auf UCA verlassen.


💩 𝔸 𝕤 𝕤 𝕦 𝕞 𝕖 𝔹 𝕣 𝕠 𝕜 𝕖 𝕖 𝕟 𝕖 𝕖 𝕤 𝕤 💩


Und das ist nicht alles. Es gibt eine Million gebrochener Annahmen, die Menschen über Unicode machen. Bis sie diese Dinge verstehen, wird ihr 🐪-Code gebrochen.

  1. Code, der davon ausgeht, dass eine Textdatei ohne Angabe der Codierung geöffnet werden kann, ist fehlerhaft.

  2. Code, der davon ausgeht, dass es sich bei der Standardcodierung um eine native Plattformcodierung handelt, ist fehlerhaft.

  3. Code, der davon ausgeht, dass Webseiten auf Japanisch oder Chinesisch in UTF-16 weniger Speicherplatz beanspruchen als in UTF-8, ist falsch.

  4. Code, der davon ausgeht, dass Perl UTF-8 intern verwendet, ist falsch.

  5. Code, der davon ausgeht, dass Codierungsfehler immer eine Ausnahme auslösen, ist falsch.

  6. Code, der davon ausgeht, dass Perl-Codepunkte auf 0x10_FFFF beschränkt sind, ist falsch.

  7. Code, der davon ausgeht, dass Sie $/etwas festlegen können , das mit einem gültigen Zeilentrennzeichen funktioniert, ist falsch.

  8. Code, der eine Roundtrip-Gleichheit beim Fallfalten voraussetzt, wie lc(uc($s)) eq $soder uc(lc($s)) eq $s, ist vollständig fehlerhaft und falsch. Bedenken Sie, dass das uc("σ")und uc("ς") beide sind "Σ", aber lc("Σ")unmöglich beide zurückgeben können.

  9. Code, der davon ausgeht, dass jeder Kleinbuchstabencode einen eindeutigen Großbuchstaben hat oder umgekehrt, ist fehlerhaft. Ist beispielsweise "ª"ein Kleinbuchstabe ohne Großbuchstaben; in der Erwägung, dass beide "ᵃ"und "ᴬ"Buchstaben sind, aber keine Kleinbuchstaben; Beide sind jedoch Kleinbuchstaben ohne entsprechende Großbuchstaben. Verstanden? Sie sind es nicht \p{Lowercase_Letter} , obwohl sie beide \p{Letter}und sind \p{Lowercase}.

  10. Code, der davon ausgeht, dass die Groß- und Kleinschreibung geändert wird, ändert nicht die Länge der Zeichenfolge.

  11. Code, der davon ausgeht, dass es nur zwei Fälle gibt, ist fehlerhaft. Es gibt auch Titelkoffer.

  12. Code, der davon ausgeht, dass nur Buchstaben Groß- und Kleinschreibung haben, ist fehlerhaft. Über Buchstaben hinaus stellt sich heraus, dass Zahlen, Symbole und sogar Markierungen Groß- und Kleinschreibung haben. In der Tat kann das Ändern des Falls sogar dazu führen, dass etwas seine allgemeine Hauptkategorie ändert, wie das \p{Mark}Verwandeln in ein \p{Letter}. Es kann auch dazu führen, dass von einem Skript zu einem anderen gewechselt wird.

  13. Code, der davon ausgeht, dass der Fall niemals vom Gebietsschema abhängig ist, ist fehlerhaft.

  14. Code, der davon ausgeht, dass Unicode eine Zahl über POSIX-Gebietsschemas enthält, ist fehlerhaft.

  15. Code, der davon ausgeht, dass Sie diakritische Zeichen entfernen können, um an ASCII-Basisbuchstaben zu gelangen, ist böse, immer noch gebrochen, hirngeschädigt, falsch und eine Rechtfertigung für die Todesstrafe.

  16. Code, der davon ausgeht, dass Diakritika \p{Diacritic}und Markierungen \p{Mark}dasselbe sind, ist fehlerhaft.

  17. Code, der davon ausgeht, \p{GC=Dash_Punctuation}deckt so viel ab, wie \p{Dash}gebrochen ist.

  18. Code, der davon ausgeht, dass Bindestriche, Bindestriche und Minuspunkte dasselbe sind oder dass es nur einen von jedem gibt, ist fehlerhaft und falsch.

  19. Code, der davon ausgeht, dass jeder Codepunkt nicht mehr als eine Druckspalte einnimmt, ist fehlerhaft.

  20. Code, der davon ausgeht, dass alle \p{Mark}Zeichen keine Druckspalten belegen, ist fehlerhaft.

  21. Code, der davon ausgeht, dass Zeichen, die gleich aussehen, gleich sind , ist fehlerhaft.

  22. Code, der davon ausgeht, dass Zeichen, die nicht gleich aussehen, nicht gleich sind, ist fehlerhaft.

  23. Code, der davon ausgeht, dass die Anzahl der Codepunkte in einer Zeile begrenzt ist, mit denen nur einer \Xübereinstimmen kann, ist falsch.

  24. Code, der davon ausgeht, dass er \Xniemals mit einem \p{Mark}Zeichen beginnen kann, ist falsch.

  25. Code, der davon ausgeht, dass er \Xniemals zwei Nichtzeichen enthalten kann \p{Mark}, ist falsch.

  26. Code, der davon ausgeht, dass er nicht verwendet werden kann, "\x{FFFF}"ist falsch.

  27. Code, der einen Nicht-BMP-Codepunkt voraussetzt, für den zwei UTF-16-Codeeinheiten (Ersatzcodeeinheiten) erforderlich sind, wird in zwei separate UTF-8-Zeichen codiert, eines pro Codeeinheit, ist falsch. Dies ist nicht der Fall: Es wird in einen einzelnen Codepunkt codiert.

  28. Code, der von UTF-16 oder UTF-32 mit führenden Stücklisten in UTF-8 transkodiert, wird beschädigt, wenn eine Stückliste am Anfang des resultierenden UTF-8 platziert wird. Das ist so dumm, dass der Ingenieur seine Augenlider entfernen lassen sollte.

  29. Code, der davon ausgeht, dass CESU-8 eine gültige UTF-Codierung ist, ist falsch. Ebenso ist Code, der glaubt, U + 0000 wie "\xC0\x80"UTF-8 zu codieren, fehlerhaft und falsch. Diese Jungs verdienen auch die Augenlidbehandlung.

  30. Code, der davon ausgeht, dass Zeichen wie >immer nach rechts und <immer nach links zeigen, ist falsch - weil dies tatsächlich nicht der Fall ist.

  31. Code, der davon ausgeht, dass, wenn Sie zuerst Zeichen Xund dann Zeichen ausgeben Y, diese als XYfalsch angezeigt werden. Manchmal tun sie es nicht.

  32. Code, der davon ausgeht, dass ASCII gut genug ist, um Englisch richtig zu schreiben, ist dumm, kurzsichtig, Analphabet, kaputt, böse und falsch. Ab mit den Köpfen! Wenn das zu extrem erscheint, können wir Kompromisse eingehen: Von nun an dürfen sie nur noch mit ihrem großen Zeh von einem Fuß aus tippen. (Der Rest wird mit Klebeband verklebt.)

  33. Code, der davon ausgeht, dass alle \p{Math}Codepunkte sichtbare Zeichen sind, ist falsch.

  34. Code, \wder nur Buchstaben, Ziffern und Unterstriche enthält, ist falsch.

  35. Code, der dies voraussetzt ^und ~Satzzeichen sind, ist falsch.

  36. Code, der davon ausgeht, dass er üeinen Umlaut hat, ist falsch.

  37. Code, der glaubt, dass Dinge wie Buchstaben Buchstaben enthalten, ist falsch.

  38. Code, der glaubt, \p{InLatin}ist der gleiche wie \p{Latin}abscheulich gebrochen.

  39. Code, der glaubt, dass er \p{InLatin}fast immer nützlich ist, ist mit ziemlicher Sicherheit falsch.

  40. Code, der glaubt, dass $FIRST_LETTERals erster Buchstabe in einem Alphabet und $LAST_LETTERals letzter Buchstabe in demselben Alphabet [${FIRST_LETTER}-${LAST_LETTER}]jede Bedeutung hat, ist fast immer vollständig gebrochen und falsch und bedeutungslos.

  41. Code, der glaubt, dass der Name einer Person nur bestimmte Zeichen enthalten kann, ist dumm, beleidigend und falsch.

  42. Code, der versucht, Unicode auf ASCII zu reduzieren, ist nicht nur falsch, sein Täter sollte nie wieder in der Programmierung arbeiten dürfen. Zeitraum. Ich bin mir nicht einmal sicher, ob sie überhaupt wieder sehen dürfen, da es ihnen bisher offensichtlich nicht viel Gutes getan hat.

  43. Code, der glaubt, dass es eine Möglichkeit gibt, so zu tun, als gäbe es keine Textdateicodierungen, ist kaputt und gefährlich. Könnte auch das andere Auge herausstechen.

  44. Code, der unbekannte Zeichen in konvertiert, ?ist kaputt, dumm, geisteskrank und widerspricht der Standardempfehlung, die besagt, dass man das nicht tun soll ! RTFM für warum nicht.

  45. Code, der glaubt, die Codierung einer nicht markierten Textdatei zuverlässig erraten zu können, ist einer fatalen Mischung aus Hybris und Naivität schuldig, die nur ein Blitz von Zeus beheben kann.

  46. Code, der glaubt, dass Sie 🐪 verwenden können printf Breiten zum und Unicode-Daten verwenden können, ist fehlerhaft und falsch.

  47. Code, der glaubt, wenn Sie erfolgreich eine Datei mit einem bestimmten Namen erstellt haben, wenn Sie lsoder ausführenreaddir sein umschließenden Verzeichnis auf, werden Sie tatsächlich , dass die Datei mit dem Namen finden Sie unter erstellt ist fehlerhaft, gebrochen und falsch. Hör auf, dich davon überraschen zu lassen!

  48. Code, der glaubt, dass UTF-16 eine Codierung mit fester Breite ist, ist dumm, kaputt und falsch. Widerrufen Sie ihre Programmierlizenz.

  49. Code, der Codepunkte aus einer Ebene anders behandelt als die aus einer anderen Ebene, ist ipso facto fehlerhaft und falsch. Zurück zur Schule gehen.

  50. Code, der glaubt, dass solche Dinge /s/inur übereinstimmen können "S"oder "s"kaputt und falsch sind. Du wärest überrascht.

  51. Code, der verwendet wird \PM\pM*, um Graphemcluster zu finden, anstatt sie zu verwenden, \Xist fehlerhaft und falsch.

  52. Menschen, die in die ASCII-Welt zurückkehren möchten, sollten von ganzem Herzen dazu ermutigt werden, und zu Ehren ihres großartigen Upgrades sollten sie kostenlos eine vorelektrische manuelle Schreibmaschine für alle ihre Dateneingabeanforderungen erhalten. An sie gesendete Nachrichten sollten über einen Telegraphen mit 40 Zeichen pro Zeile gesendet und von einem Kurier per Hand zugestellt werden. HALT.


😱 𝕾 𝖀 𝕸 𝕸 𝕸 𝕽 𝕽 𝖄


Ich weiß nicht, wie viel mehr "Standard-Unicode in 🐪" Sie bekommen können, als ich geschrieben habe. Nun ja, das tue ich: du solltest Unicode::Collateund verwendenUnicode::LineBreak auch. Und wahrscheinlich mehr.

Wie Sie sehen, gibt es viel zu viele Unicode-Dinge, über die Sie sich wirklich Sorgen machen müssen, als dass es sie jemals geben könnte so etwas wie „Standard für Unicode“ geben könnte.

Was Sie genau wie in 🐪 5.8 entdecken werden, ist, dass es einfach unmöglich ist, all diese Dinge Code aufzuzwingen, der nicht von Anfang an entwickelt wurde, um sie zu berücksichtigen. Ihre wohlmeinende Selbstsucht hat gerade die ganze Welt zerstört.

Und selbst wenn Sie dies tun, gibt es immer noch kritische Probleme, die viel Nachdenken erfordern, um richtig zu werden. Es gibt keinen Schalter, den Sie umlegen können. Nichts als Gehirn, und ich meine echtes Gehirn , wird hier ausreichen. Es gibt eine Menge Dinge, die man lernen muss. Modulo der Rückzug zur manuellen Schreibmaschine, kann man einfach nicht hoffen, in Unwissenheit vorbei zu schleichen. Dies ist das 21. Jahrhundert, und Sie können Unicode nicht durch vorsätzliche Unwissenheit wegwünschen.

Du musst es lernen. Zeitraum. Es wird nie so einfach sein, dass „alles einfach funktioniert“, denn das garantiert, dass viele Dinge nicht funktionieren funktionieren - was die Annahme ungültig macht, dass es jemals einen Weg geben kann, „alles zum Laufen zu bringen“.

Möglicherweise können Sie einige vernünftige Standardeinstellungen für sehr wenige und sehr begrenzte Vorgänge erhalten, aber nicht ohne viel mehr über die Dinge nachzudenken, als ich denke, dass Sie dies getan haben.

Als nur ein Beispiel wird die kanonische Reihenfolge einige echte Kopfschmerzen verursachen. 😭 "\x{F5}" 'õ' , "o\x{303}" 'õ' , "o\x{303}\x{304}" 'ȭ' und "o\x{304}\x{303}" 'ō̃' sollten alle mit 'õ' übereinstimmen , aber wie in aller Welt werden Sie das tun? Das ist schwieriger als es aussieht, aber es ist etwas, das Sie berücksichtigen müssen. 💣

Wenn ich etwas über Perl weiß, dann ist es das, was seine Unicode-Bits tun und was nicht, und dieses verspreche ich Ihnen: „̲ᴛ̲ʜ̲ᴇ̲ʀ̲ᴇ̲ ̲ɪ̲s̲ ̲ɴ̲ᴏ̲ ̲U̲ɴ̲ɪ̲ᴄ̲ᴏ̲ᴅ̲ᴇ̲ ̲ᴍ̲ᴀ̲ɢ̲ɪ̲ᴄ̲ ̲ʙ̲ᴜ̲ʟ̲ʟ̲ᴇ̲ᴛ̲ ̲“ 😞

Sie können nicht einfach einige Standardeinstellungen ändern und reibungslos segeln. Es ist wahr, dass ich set mit PERL_UNICODEset to starte "SA", aber das ist alles, und selbst das ist meistens für Kommandozeilen-Sachen. Für echte Arbeit gehe ich alle oben beschriebenen Schritte durch und mache es sehr, sehr, sehr sorgfältig.


😈 ¡ƨdləɥ ƨᴉɥʇ ədoɥ puɐ λɐp əɔᴉu ɐ ʞɔnl poo⅁ 😈

tchrist
quelle
56
Wie Sherm Pendley zeigte: "Alle!". Wenn ich heute etwas Neues schreibe, sollte UTF-8 der einfachste Weg sein, Dinge zu erledigen. Es ist nicht. Ihr Boilerplate beweist es. Nicht jeder hat das Wissen, um so viele Becher in die richtige Position zu bringen. Es tut mir leid, ich hatte einen langen und harten Tag, also werde ich morgen im Haupteintrag mehr mit Beispielen kommentieren.
Woche
17
Eine Schlussfolgerung sollte aus dem Lesen der obigen Liste ersichtlich sein: Nicht in Groß- und Kleinschreibung. Tu es einfach nicht. Je. Rechenintensiv und mit einer Semantik, die entscheidend davon abhängt, was "locale" erfolglos zu identifizieren versucht.
Tim Bray
72
Bin ich der einzige, der es ironisch findet, dass dieser Beitrag von tchrist auf FF / Chrome / IE / Opera so wild anders aussieht, dass er irgendwann unleserlich wird?
Damageboy
15
Während ich die Post im Allgemeinen mag und positiv gestimmt habe, nervt mich eine Sache zum Teufel. Es gibt viel "Code, der ... kaputt ist". Ich argumentiere zwar nicht mit der Aussage, aber ich denke, es wäre gut, die Zerbrochenheit zu zeigen. Auf diese Weise würde es (dieser Teil der Antwort) von einem Geschwätz zur Bildung übergehen.
36
@xenoterracide Nein, ich habe keine absichtlich problematischen Codepunkte verwendet. Es ist eine Handlung, mit der Sie George Douros 'großartige Symbola-Schriftart installieren können , die Unicode 6.0 abdeckt. 😈 @depesz Hier ist kein Platz, um zu erklären, warum jeder gebrochene Angriff falsch ist. @leonbloy Viele, viele dieser gilt für Unicode in der Regel nicht nur Perl. Ein Teil dieses Materials wird möglicherweise in „Programming Perl“, 4. Ausgabe , erscheinen und im Oktober erscheinen. 🎃 Ich habe noch einen Monat Zeit, um daran zu arbeiten, und Unicode ist da. Regexes auch
Tchrist
96

Die Verarbeitung von Unicode-Text erfolgt in zwei Schritten. Das erste ist "Wie kann ich es eingeben und ausgeben, ohne Informationen zu verlieren". Die zweite lautet: "Wie behandle ich Text gemäß den Konventionen der Landessprache?"

Der Beitrag von tchrist deckt beide ab, aber im zweiten Teil stammen 99% des Textes in seinem Beitrag. Die meisten Programme verarbeiten E / A nicht einmal richtig, daher ist es wichtig zu verstehen, bevor Sie sich überhaupt Gedanken über Normalisierung und Sortierung machen.

Dieser Beitrag zielt darauf ab, dieses erste Problem zu lösen

Wenn Sie Daten in Perl einlesen, ist es egal, um welche Codierung es sich handelt. Es reserviert etwas Speicher und versteckt die Bytes dort. Wenn Sie sagen print $str, werden diese Bytes nur an Ihr Terminal ausgegeben, was wahrscheinlich davon ausgeht, dass alles, was darauf geschrieben wird, UTF-8 ist, und Ihr Text wird angezeigt.

Wunderbar.

Außer es ist nicht. Wenn Sie versuchen, die Daten als Text zu behandeln, werden Sie feststellen, dass etwas Schlimmes passiert. Sie müssen nicht weiter gehen, als lengthzu sehen, dass das, was Perl über Ihre Saite denkt und was Sie über Ihre Saite denken, nicht übereinstimmt. Schreiben Sie einen Einzeiler wie: perl -E 'while(<>){ chomp; say length }'und geben Sie ein文字化け und Sie erhalten 12 ... nicht die richtige Antwort, 4.

Das liegt daran, dass Perl davon ausgeht, dass Ihre Zeichenfolge kein Text ist. Sie müssen ihm sagen, dass es sich um Text handelt, bevor Sie die richtige Antwort erhalten.

Das ist einfach genug; Das Encode-Modul verfügt über die entsprechenden Funktionen. Der generische Einstiegspunkt ist Encode::decode(oderuse Encode qw(decode) natürlich). Diese Funktion nimmt eine Zeichenfolge aus der Außenwelt (was wir "Oktette" nennen, eine ausgefallene Art, "8-Bit-Bytes" zu sagen) und wandelt sie in einen Text um, den Perl verstehen wird. Das erste Argument ist ein Zeichencodierungsname wie "UTF-8" oder "ASCII" oder "EUC-JP". Das zweite Argument ist die Zeichenfolge. Der Rückgabewert ist der Perl-Skalar, der den Text enthält.

(Es gibt auch Encode::decode_utf8UTF-8 für die Codierung.)

Wenn wir unseren Einzeiler umschreiben:

perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }'

Wir geben 文字 化 け ein und erhalten als Ergebnis "4". Erfolg.

Genau dort ist die Lösung für 99% der Unicode-Probleme in Perl.

Der Schlüssel ist, wann immer Text in Ihr Programm kommt, müssen Sie ihn dekodieren. Das Internet kann keine Zeichen übertragen. Dateien können keine Zeichen speichern. Ihre Datenbank enthält keine Zeichen. Es gibt nur Oktette, und Sie können Oktette in Perl nicht als Zeichen behandeln. Sie müssen die codierten Oktette mit dem Encode-Modul in Perl-Zeichen dekodieren.

Die andere Hälfte des Problems besteht darin, Daten aus Ihrem Programm abzurufen. Das ist einfach; Sie sagen einfach use Encode qw(encode), entscheiden Sie , in welcher Codierung Ihre Daten enthalten sein sollen (UTF-8 für Terminals, die UTF-8, UTF-16 für Windows-Dateien usw. verstehen), und geben dann das Ergebnis aus, encode($encoding, $data)anstatt nur auszugeben $data.

Diese Operation konvertiert Perls Zeichen, mit denen Ihr Programm arbeitet, in Oktette, die von der Außenwelt verwendet werden können. Es wäre viel einfacher, wenn wir nur Zeichen über das Internet oder an unsere Terminals senden könnten, aber wir können nicht: nur Oktette. Wir müssen also Zeichen in Oktette konvertieren, sonst sind die Ergebnisse undefiniert.

Zusammenfassend: Kodieren Sie alle Ausgänge und dekodieren Sie alle Eingänge.

Jetzt werden wir über drei Themen sprechen, die dies ein wenig herausfordernd machen. Das erste sind Bibliotheken. Behandeln sie Text richtig? Die Antwort ist ... sie versuchen es. Wenn Sie eine Webseite herunterladen, erhalten Sie von LWP Ihr Ergebnis als Text zurück. Wenn Sie die richtige Methode für das Ergebnis aufrufen, ist dies (und das ist zufällig decoded_contentnicht contentder Oktett-Stream, den es vom Server erhalten hat). Datenbanktreiber können unzuverlässig sein. Wenn Sie DBD :: SQLite nur mit Perl verwenden, wird es funktionieren, aber wenn ein anderes Tool Text als andere Codierung als UTF-8 in Ihre Datenbank aufgenommen hat ... nun ... wird es nicht richtig gehandhabt bis Sie Code schreiben, um damit richtig umzugehen.

Die Ausgabe von Daten ist normalerweise einfacher, aber wenn Sie "breites Zeichen im Druck" sehen, wissen Sie, dass Sie die Codierung irgendwo durcheinander bringen. Diese Warnung bedeutet "Hey, du versuchst Perl-Charaktere nach außen zu lecken und das macht keinen Sinn". Ihr Programm scheint zu funktionieren (weil das andere Ende normalerweise die rohen Perl-Zeichen korrekt verarbeitet), aber es ist sehr kaputt und kann jeden Moment nicht mehr funktionieren. Beheben Sie es mit einem expliziten Encode::encode!

Das zweite Problem ist UTF-8-codierter Quellcode. Wenn Sie nicht use utf8oben in jeder Datei sagen , geht Perl nicht davon aus, dass Ihr Quellcode UTF-8 ist. Dies bedeutet, dass Sie jedes Mal, wenn Sie so etwas sagen my $var = 'ほげ', Müll in Ihr Programm injizieren, der alles schrecklich kaputt macht. Sie müssen nicht auf „Verwendung utf8“, aber wenn Sie das nicht tun, Sie müssen keine Nicht-ASCII - Zeichen in Ihrem Programm verwenden.

Das dritte Problem ist, wie Perl mit The Past umgeht. Vor langer Zeit gab es kein Unicode, und Perl nahm an, dass alles Latin-1-Text oder Binär war. Wenn also Daten in Ihr Programm eingehen und Sie beginnen, sie als Text zu behandeln, behandelt Perl jedes Oktett als Latin-1-Zeichen. Deshalb haben wir, als wir nach der Länge von "文字 化 け" gefragt haben, 12 bekommen. Perl nahm an, dass wir mit der Latin-1-Zeichenfolge "æååã" arbeiten (12 Zeichen, von denen einige nicht gedruckt werden).

Dies wird als "implizites Upgrade" bezeichnet und ist durchaus sinnvoll, aber es ist nicht das, was Sie wollen, wenn Ihr Text nicht Latin-1 ist. Aus diesem Grund ist es wichtig, Eingaben explizit zu dekodieren: Wenn Sie dies nicht tun, wird Perl dies tun, und es kann sein, dass es falsch ist.

Menschen geraten in Schwierigkeiten, wenn die Hälfte ihrer Daten eine richtige Zeichenfolge ist und einige immer noch binär. Perl interpretiert den Teil, der noch binär ist, als wäre es Latin-1-Text, und kombiniert ihn dann mit den richtigen Zeichendaten. Dadurch sieht es so aus, als ob der richtige Umgang mit Ihren Charakteren Ihr Programm kaputt gemacht hat, aber in Wirklichkeit haben Sie es einfach nicht genug behoben.

Hier ein Beispiel: Sie haben ein Programm, das eine UTF-8-codierte Textdatei liest, Sie kleben einen Unicode PILE OF POOan jede Zeile und drucken ihn aus. Du schreibst es wie:

while(<>){
    chomp;
    say "$_ 💩";
}

Führen Sie dann einige UTF-8-codierte Daten aus, z.

perl poo.pl input-data.txt

Es druckt die UTF-8-Daten mit einem Poo am Ende jeder Zeile. Perfekt, mein Programm funktioniert!

Aber nein, Sie machen nur binäre Verkettung. Sie lesen Oktette aus der Datei, entfernen ein \nmit chomp und heften dann die Bytes in der UTF-8-Darstellung des PILE OF POOZeichens an. Wenn Sie Ihr Programm überarbeiten, um die Daten aus der Datei zu dekodieren und die Ausgabe zu kodieren, werden Sie feststellen, dass Sie Müll ("ð ©") anstelle von poo erhalten. Dies lässt Sie glauben, dass das Dekodieren der Eingabedatei falsch ist. Es ist nicht.

Das Problem ist, dass der Poo implizit als Latin-1 aktualisiert wird. Wenn Sie use utf8den wörtlichen Text anstelle des Binärtextes erstellen, funktioniert er wieder!

(Das ist das Hauptproblem, das ich sehe, wenn ich Menschen mit Unicode helfe. Sie haben sich richtig getrennt und das hat ihr Programm gebrochen. Das ist das Traurige an undefinierten Ergebnissen: Sie können ein funktionierendes Programm für eine lange Zeit haben, aber wenn Sie anfangen, es zu reparieren, Keine Sorge, wenn Sie Ihrem Programm Codierungs- / Dekodierungsanweisungen hinzufügen und es kaputt geht, bedeutet dies nur, dass Sie mehr Arbeit zu erledigen haben. Wenn Sie das nächste Mal von Anfang an mit Unicode arbeiten, wird dies der Fall sein viel einfacher!)

Das ist wirklich alles, was Sie über Perl und Unicode wissen müssen. Wenn Sie Perl mitteilen, was Ihre Daten sind, bietet es die beste Unicode-Unterstützung unter allen gängigen Programmiersprachen. Wenn Sie davon ausgehen, dass es auf magische Weise weiß, welche Art von Text Sie ihm zuführen, werden Sie Ihre Daten unwiderruflich in den Papierkorb werfen. Nur weil Ihr Programm heute auf Ihrem UTF-8-Terminal funktioniert, heißt das nicht, dass es morgen auf einer UTF-16-codierten Datei funktioniert. Machen Sie es jetzt sicher und ersparen Sie sich die Kopfschmerzen, die Daten Ihrer Benutzer zu zerstören!

Der einfache Teil der Handhabung von Unicode ist das Codieren der Ausgabe und das Decodieren der Eingabe. Der schwierige Teil besteht darin, alle Ihre Ein- und Ausgaben zu finden und zu bestimmen, um welche Codierung es sich handelt. Aber deshalb bekommst du das große Geld :)

Jrockway
quelle
Das Prinzip ist gut erklärt, aber der praktische Ansatz für E / A fehlt. Die explizite Verwendung des EncodeModuls ist mühsam und fehleranfällig und macht das Lesen des Codes für E / A sehr schmerzhaft. E / A-Schichten bieten eine Lösung, da sie bei Bedarf transparent codieren und decodieren. openund binmodelassen Sie ihre Spezifikation zu, und Pragma openlegt die Standardeinstellungen fest, wie tchrist in seiner Antwort empfiehlt.
Palec
48

Wir sind uns alle einig, dass es aus vielen Gründen ein schwieriges Problem ist, aber genau das ist der Grund, es allen leichter zu machen.

In CPAN gibt es ein aktuelles Modul, utf8 :: all , das versucht, "Unicode einzuschalten. All das".

Wie bereits erwähnt, können Sie nicht auf magische Weise das gesamte System (externe Programme, externe Webanforderungen usw.) dazu bringen, Unicode zu verwenden. Wir können jedoch zusammenarbeiten, um sinnvolle Tools zu entwickeln, die das Beheben allgemeiner Probleme erleichtern. Das ist der Grund, warum wir Programmierer sind.

Wenn utf8 :: all etwas nicht tut, was Sie denken, dass es sollte, verbessern wir es, um es besser zu machen. Oder lassen Sie uns zusätzliche Tools erstellen, die zusammen den unterschiedlichen Bedürfnissen der Menschen so gut wie möglich entsprechen.

`

Randy Stauner
quelle
5
Ich sehe im genannten Modul viel Raum für Verbesserungenutf8::all . Es wurde vor dem unicode_stringsFeature geschrieben, das Fɪɴᴀʟʟʏ ᴀɴᴅ ᴀɴᴅ Lᴏɴɢ Lᴀsᴛ Regexes korrigiert, um ein /uauf ihnen zu haben . Ich bin nicht davon überzeugt, dass es eine Ausnahme bei Codierungsfehlern gibt, und das müssen Sie wirklich haben. Es wird nicht in das use charnames ":full"Pragma geladen , das noch nicht automatisch geladen wurde. Es warnt nicht vor [a-z]und so, printfZeichenfolgenbreiten, \nanstelle von \Rund .anstelle von \X, aber vielleicht sind diese eher eine Perl::CriticFrage. Wenn ich es wäre, würde ich 𝐍𝐅𝐃 rein und 𝐍𝐅𝐂 raus hinzufügen.
Tchrist
13
@tchrist Der Issue-Tracker für utf8 :: all ist hier. github.com/doherty/utf8-all/issues Sie würden gerne Ihre Vorschläge hören.
Schwern
4
@Schwern: ᴇɴᴏᴛᴜɪᴛs, aber zögern Sie nicht, die Sachen, die ich hier geschrieben habe, zu stehlen und zu kneifen. Um ehrlich zu sein, fühle / lerne ich immer noch, was getan werden kann und was getan werden sollte und wo. Hier ist ein schönes Beispiel für das Auslagern der Sortierung : unichars -gs '/(?=\P{Ll})\p{Lower}|(?=\P{Lu})\p{Upper}/x' | ucsort --upper | cat -n | less -r. Ebenso können kleine Vorverarbeitungsschritte wie ... | ucsort --upper --preprocess='s/(\d+)/sprintf "%#012d", $1/ge'auch sehr schön sein, und ich möchte nicht die Entscheidungen anderer für sie treffen. Ich baue immer noch meine Unicode-Toolbox .
Tchrist
35

Ich denke, Sie verstehen Unicode und seine Beziehung zu Perl falsch. Egal auf welche Weise Sie Daten speichern, Unicode, ISO-8859-1 oder viele andere Dinge , muss Ihr Programm wissen, wie es die Bytes interpretiert, die es als Eingabe erhält (Decodierung) und wie es die Informationen darstellt, die es ausgeben möchte (Codierung) ). Verstehen Sie diese Interpretation falsch und Sie verstümmeln die Daten. Es gibt kein magisches Standard-Setup in Ihrem Programm, das den Dingen außerhalb Ihres Programms sagt, wie sie sich verhalten sollen.

Sie denken, es ist höchstwahrscheinlich schwierig, weil Sie daran gewöhnt sind, dass alles ASCII ist. Alles, worüber Sie hätten nachdenken sollen, wurde von der Programmiersprache und all den Dingen, mit denen sie interagieren musste, einfach ignoriert. Wenn alles nur UTF-8 verwenden würde und Sie keine andere Wahl hätten, wäre UTF-8 genauso einfach. Aber nicht alles verwendet UTF-8. Zum Beispiel möchten Sie nicht, dass Ihr Eingabe-Handle denkt, dass es UTF-8-Oktette erhält, es sei denn, dies ist tatsächlich der Fall, und Sie möchten nicht, dass Ihre Ausgabe-Handles UTF-8 sind, wenn das von ihnen gelesene Objekt UTF-8 verarbeiten kann . Perl hat keine Möglichkeit, diese Dinge zu wissen. Deshalb bist du der Programmierer.

Ich denke nicht, dass Unicode in Perl 5 zu kompliziert ist. Ich finde es beängstigend und die Leute meiden es. Es besteht ein Unterschied. Zu diesem Zweck habe ich Unicode in Learning Perl, 6. Ausgabe , eingefügt , und es gibt viele Unicode-Inhalte in Effective Perl Programming . Sie müssen sich die Zeit nehmen, um Unicode zu lernen und zu verstehen und wie es funktioniert. Sie werden es sonst nicht effektiv nutzen können.

brian d foy
quelle
3
Ich denke, Sie haben einen Punkt: Es ist beängstigend. Sollte es sein? Für mich ist Unicode-Segen, die Verwendung in Perl5 nicht (ich gehe nicht davon aus, dass etwas ASCII ist, meine Muttersprache benötigt mindestens iso8859-4). Ich habe Rakudo installiert und alles, was ich mit UTF-8 (in dieser begrenzten Sandbox) versucht habe, hat sofort funktioniert. Habe ich etwas verpasst? Ich betone es noch einmal: Es ist gut, die Unicode-Unterstützung fein abgestimmt zu haben, aber in den meisten Fällen ist dies nicht erforderlich. Um die Angst vor dem Thema loszuwerden, besteht eine Möglichkeit darin, dass jeder viel liest, um Interna zu verstehen. Sonstiges: Wir haben ein besonderes Pragma, das use utf8_everywheredie Menschen glücklich macht. Warum nicht der letzte?
wk
3
Ich denke immer noch, dass Sie den Punkt verfehlen. Was hat funktioniert? Sie müssen Interna nicht verstehen. Sie müssen externe Elemente verstehen und wissen, wie Sie mit Zeichenfolgen umgehen sollen, die unterschiedliche Codierungen und unterschiedliche Darstellungen derselben Zeichen aufweisen. Lesen Sie Toms Rat noch einmal. Das meiste, was er sagt, ich wette, Sie werden feststellen, dass Rakudo nichts für Sie erledigt.
Brian D Foy
1
@wk: Lies Randys Antwort noch einmal. Er hat dir bereits gesagt, wo die Grenzen liegen.
Brian D Foy
2
@brian d foy: Ich denke, dass diese Einschränkungen in Ordnung sind, wie Tchrist sagt, es gibt kein Wundermittel für jeden Aspekt (ich gebe zu: Ich habe die meisten nicht gesehen, bevor ich diese Frage hier gestellt habe). Wenn wir also viele grundlegende Dinge mit so etwas wie utf8 :: all behandeln, muss nicht jeder sein eigenes großes Boilerplate bauen, nur um die Grundlagen des utf8-Handlings zum Laufen zu bringen. Mit "überhaupt keine Angst" meine ich: Jeder kann seine Projekte starten, wenn er weiß, dass die Grundlagen abgedeckt sind. Ja, Sie haben Recht, es gibt immer noch viele Probleme. Aber wenn der Start einfacher ist, werden mehr Leute an der Lösung dieser Probleme beteiligt sein. IMHO
Woche
1
@wk - das einzige "Falsche" mit "utf8: all" oder "uni :: perl" ist nur eins - sie befinden sich nicht im KERN - also muss jeder es vom CPAN installieren. Und wenn Sie denken, dass dies kein großes ist Deal - bitte überdenken - ja, es ist einfacher, utf8 mit einem Hilfsmodul zu verwenden. Ohne es hat das CORE Perl immer noch Unicode-Unterstützung - aber sehr viel kompliziert. Und das ist falsch.
jm666
28

Beim Lesen dieses Threads habe ich oft den Eindruck, dass Leute " UTF-8 " als Synonym für " Unicode " verwenden. Bitte unterscheiden Sie zwischen den "Code-Punkten" von Unicode, die ein vergrößerter Verwandter des ASCII-Codes sind, und den verschiedenen "Codierungen" von Unicode. Und es gibt einige davon, von denen UTF-8, UTF-16 und UTF-32 die aktuellen sind und einige weitere veraltet sind.

Bitte, UTF-8 (sowie alle anderen Codierungen ) existiert und hat nur in der Eingabe oder in der Ausgabe eine Bedeutung. Intern werden seit Perl 5.8.1 alle Zeichenfolgen als Unicode- "Codepunkte" beibehalten. Es stimmt, Sie müssen einige Funktionen aktivieren, die zuvor bewundernswert behandelt wurden.

MeirG
quelle
19
Ich bin damit einverstanden, dass Leute Uɴɪᴄᴏᴅᴇ zu oft mit UTF-8⧸16⧸32 verwechseln, aber es ist grundsätzlich und kritisch nicht wahr, dass Uɴɪᴄᴏᴅᴇ nur ein vergrößerter Zeichensatz relativ zu ᴀsᴄɪɪ ist. Das ist höchstens nichts anderes als ɪsᴏ-10646 . Uɴɪᴄᴏᴅᴇ enthält viel mehr : Regeln für Kollatierung, Fallfaltung, Normalisierungsformen, Graphemcluster, Wort- und Zeilenumbruch, Skripte, numerische Äquivalente, Breiten, Bidirektionalität, Glyphenvarianten, Kontextverhalten, Gebietsschemas, Regexe, Kombinieren von Klassen, Hunderte von Eigenschaften und viel mehr‼
tchrist
15
@tchrist: Der erste Schritt besteht darin, Daten in Ihr Programm und nach außen zu übertragen, ohne sie zu zerstören. Dann können Sie sich um Kollatierung, Fallfaltung, Glyphenvarianten usw. kümmern.
Jrockway
7
Ich bin damit einverstanden, dass es die erste Priorität sein muss, dass Perl die Eingabe oder Ausgabe nicht in den Papierkorb wirft. Ich hätte gerne ein Modul oder Pragma, das die folgende fiktive Konversation verkörpern könnte: "- Lieber Perl. Für dieses Programm werden alle Ein- und Ausgaben ausschließlich UTF-8 sein. Könnten Sie bitte meine Daten nicht in den Papierkorb werfen? - Also nur UFT-8, sagst du. Bist du sicher? - Ja. - Wirklich, wirklich sicher? - Absolut. - Und du akzeptierst, dass ich mich seltsam verhalten könnte, wenn mir Nicht-UTF-8-Daten zugestellt werden? - Ja, gut. - OK dann."
Hlovdal
10

Es gibt eine wirklich schreckliche Menge an altem Code in freier Wildbahn, viel davon in Form gängiger CPAN-Module. Ich habe festgestellt, dass ich ziemlich vorsichtig sein muss, um Unicode zu aktivieren, wenn ich externe Module verwende, die davon betroffen sein könnten, und immer noch versuche, einige Unicode-bezogene Fehler in mehreren Perl-Skripten zu identifizieren und zu beheben, die ich regelmäßig verwende (insbesondere iTiVo schlägt fehl schlecht auf alles, was aufgrund von Transcodierungsproblemen nicht 7-Bit-ASCII ist).

Geekosaurier
quelle
Ich wollte die -COption verwenden, um sicherzustellen, dass Perl auf derselben Seite ist wie ich, was Unicode betrifft, da ich mich weiterhin dafür entscheide, ISO 8859/1 anstelle von Unicode zu verwenden, obwohl ich dies explizit $LANGund $LC_ALLrichtig einstelle . (Dies kann tatsächlich Fehler in den Bibliotheken des Plattformgebietsschemas widerspiegeln.) Was auch immer es ist, es war sehr ärgerlich, dass ich iTivo nicht für Programme mit Akzenten verwenden kann, da die Perl-Skripte, die die Arbeit erledigen, mit Konvertierungsfehlern umfallen.
Geekosaurier
3
Ein Einzelgänger -Cohne Optionen ist fehlerhaft und fehleranfällig . Du brichst die Welt. Setzen Sie die PERL5OPTVariable auf -Cund Sie werden sehen, was ich meine. Wir haben es in Version 5.8 auf diese Weise versucht, und es war eine Katastrophe. Sie können und dürfen Programmen, die dies nicht erwarten, einfach nicht mitteilen, dass sie sich jetzt mit Unicode befassen, ob sie es mögen oder nicht. Es gibt auch Sicherheitsprobleme. Zumindest wird alles, was tut print while <>, kaputt gehen, wenn Binärdaten übergeben werden. Dies gilt auch für den gesamten Datenbankcode. Das ist eine schreckliche Idee.
Tchrist
1
Ich habe generisch gesprochen, eigentlich nicht speziell -Cohne Optionen. Die spezifische Anrufung, mit der ich gearbeitet hatte, war -CSDA. Das heißt, ich war lange Zeit mit 5.8.x festgefahren (hallo MacPorts ...), also war das vielleicht ein Teil davon.
Geekosaurier
1
Ich laufe mit PERL_UNICODE auf SA gesetzt. Sie können NICHT es D. gesetzt
tchrist
@tchrist: Einige Perl-Varmint haben einen Code veröffentlicht, der die Verwendung von -CSDA und PERL_UNICODE = SDA anzeigt . Bitte nutzen Sie Ihren Einfluss in der Community. Er muss gestoppt werden!
Ashley
1

Sie sollten die Funktion für Unicode-Zeichenfolgen aktivieren. Dies ist die Standardeinstellung, wenn Sie Version 5.14 verwenden.

Sie sollten nicht wirklich Unicode-Bezeichner verwenden, insb. für fremden Code über utf8, da sie in perl5 unsicher sind, hat nur cperl das richtig verstanden. Siehe z. B. http://perl11.org/blog/unicode-identifiers.html

Zu utf8 für Ihre Dateihandles / Streams: Sie müssen die Kodierung Ihrer externen Daten selbst festlegen. Eine Bibliothek kann das nicht wissen, und da nicht einmal libc utf8 unterstützt, sind richtige utf8-Daten selten. Es gibt mehr wtf8, die Windows-Aberration von utf8.

Übrigens: Moose ist nicht wirklich "Modern Perl", sie haben nur den Namen entführt. Moose ist das perfekte postmoderne Perl im Larry Wall-Stil, gemischt mit Bjarne Stroustrup-Stil, mit einer eklektischen Aberration der richtigen Perl6-Syntax, z. B. der Verwendung von Strings für Variablennamen, der Syntax für schreckliche Felder und einer sehr unreifen naiven Implementierung, die 10x langsamer ist als a ordnungsgemäße Umsetzung. cperl und perl6 sind die wahren modernen Perls, bei denen die Form der Funktion folgt und die Implementierung reduziert und optimiert wird.

rurban
quelle