!init OPT_STYLE="paper" !define DOC_NAME "Perl und Unicode - eine gefährliche Mischung" !define DOC_AUTHOR "Marc Lehmann " !build_title H1: Encoding, Charsets, Glyphs Unicode, UTF-8 u.ä. wird oft in einen Topf geworfen. Das ist meist einfach und auch in Ordnung, wenn man die feinen Unterscheide kennt. Weil ich hier etwas genauer sein will, möchte ich zuerst einige Begriffe klären: * Charset (Zeichensatz). Ein Zeichensatz ist eine Menge von Zeichen in einer bestimmten Reihenfolge. Dadurch bekommt jedes Zeichen eine eindeutige Nummer. Unicode ist z.B. ein Zeichensatz. Das 9729te davon ist z.B. das Zeichen "CLOUD" (Wolke). * Encoding (Kodierung). Irgendwie werden diese Zeichennummern gespeichert. Bei vielen Zeichensätzen (z.B. ASCII = 128 Zeichen oder ISO-8859-1 = 256 Zeichen) reicht ein Byte (bzw. octet) aus. Hat man keine ungewöhnliche Rechnerarchitektur erscheint das natürlich. Bei Unicode (z.Zt. 524288 Zeichen!) geht das nicht mehr, eine "natürliche" Form der Speicherung gibt es nicht, deshalb gibt es mehrere Methoden, Zeichennummern auf Bytes abzubilden. Eine solche Methode ist ein "Encoding". UTF-8/UTF-16 oder UCS-4 sind Encodings. (UCS-2 hört man ebenfalls häufig, kann aber nur die ersten 2**16 Unicode-Zeichen darstellen und sollte nicht mehr verwendet werden). * Glyph. Das Unicode-Zeichen Nummer 9729 stellt eine Wolke dar. Wolken können je nach Font (Schrift) unterschiedlich aussehen. Ein Glyph ist nur eine Form oder eine Grafik, die den einzelnen Nummern zugeordnet werden. Mit Glyphen hat Perl nicht allzuviel zu tun. H2: Unicode Unicode wurde ursprünglich ins Leben gerufen, um mit der Vielfalt der Zeichensätze aufzuräumen, um {{einen}} Standard-Zeichensatz für praktisch alle Fälle zu erhalten. Mit Unicode ist es erstmals möglich, auch komplexe Texte (in mehreren Sprachen) in {{einem}} Zeichensatz zu verfassen, z.B. um ein Originalzitat von Gogol (in kyrillisch) in einem französischen Artikel unterzubringen. Dass man letzteres braucht hat mir erst Christian Kirsch erklären müssen, denn ich dachte immer, Gogols wären große Zahlen und keine Originalzitate... Unicode verbessert also auch die Allgemeinbildung ;) Die Normungsgruppe für den ISO-Standard 10646 (den Nachfolger von ISO-646, auch ASCII genannt ;) versuchte ebenfalls, einen Universalzeichensatz zu erstellen. Unicode hatte ursprünglich 16 Bit, ISO-10646 ursprünglich 31. Anfänglich gab es große Ablehnung gegen beide Vorhaben, meist, weil gleich aussehende Glyphen zu einem Zeichen zusammengefasst wurden - ein Unding. Aber ernsthaft: es gab viele kleine Fehler, die inzwischen größtenteils beseitigt wurden, so dass Unicode nicht mehr auf starke Ablehnung stößt. Da ISO-10646 niemals wirkliche Ergebnisse vorweisen konnte, wurde ISO-10646 mehr oder weniger als Unicode definiert und der Rest (ein ISO-10646-Zeichen umfaßt 31 Bit, ein paar mehr als Unicode!) der Zeichen blieb unbelegt. Unicode wurde mittlerweile auf 18 Bit erweitert (das war von Anfang an so vorgesehen, jedoch wurden die Zeichen anfänglich nicht belegt). H2: UTF-8 Eine spezielle Kodierung von Unicode ist UTF-8. Meiner ganz persönlichen und deshalb objektiven Meinung nach hat UTF-8 einige absolut geniale Eigenschaften{{}}: * es gibt keine eingebetteten Nullen. Die meisten Funktionen, die auf nullterminierte 8-Bit-Strings angewendet werden, können auch sinnvoll auf UTF-8 angewendet werden. * ASCII-Zeichen bleiben ASCII. Man kann immer noch nach "+" oder "$" suchen (einfache Parser). Wenn ein Byte im String den Wert 97 hat, ist es ein kleines "a". * UTF-8 ist platzsparend: ASCII belegt ein, die meisten ISO-Zeichensätze zwei Byte pro Zeichen und mit drei Byte kann man fast alle belegten Unicode-Zeichen erreichen (inklusive der meisten asiatischen Zeichen). Mit vier Byte lassen sich alle Unicode-Zeichen erreichen. * UTF-8 ist sicher: man kann jederzeit festellen, ob man sich am Anfang eines Multibyte-Zeichens oder in der Mitte befindet. So kann man auch mitten in einem String aufsetzen und resynchronisieren. Außerdem ist die Verwechslung von UTF-8 mit anderen Kodierungen unwahrscheinlich: ist ein Byte-Stream formal gültiges UTF-8, ist es mit hoher Wahrscheinlichkeit tatsächlich UTF-8 und nicht etwas anderes, wie ein JPEG-Bild oder Latin1 mit Umlauten. * Die Sortierreihenfolge wird auch bei strcmp (nicht-UTF-8-"cmp"-operator) eingehalten. Das hat in der Praxis allerdings geringe Bedeutung. UTF-8 nimmt also immer gleichviel oder weniger Platz ein als UCS-4 (4 Byte/Zeichen). UTF-16 ist manchmal kürzer, dafür handelt man sich aber mehr Nachteile ein (Multiword statt Multibyte, embeddete Nullen, Byteorder!). Speicherersparnis bringt auf neueren Architekturen meistens auch Zeitersparnis, so dass in den meisten Fällen UTF-8 sowohl UTF-16 als auch UCS-4 vorzuziehen ist, auch wenn die Algorithmen teilweise komplizierter werden. H1: Perl Perl - eine tolle Sprache, und sie kann auch Multibyte-Zeichen. Aber das leider nur sehr, sehr umständlich. Eine natürliche Implementation, bei dem einem der Perl-Interpreter die Arbeit abnimmt, wäre da toll. So dachte sich wohl Larry und baute UTF-8-Unterstützung in Perl ein. Das sah so aus, dass man in allen Programmteilen, die unter dem Einfluss eines {{C:use utf8}} standen, UTF-8-Semantik hatte, woanders jedoch nicht. Das hätte erfordert, dass man alle Module, die UTF-8-fähig werden sollten, umschreiben müsste. Um dem zu entgehen, wurde das Unicode-Modell von Perl geändert: Ein jeder Skalar weiß nun darüber Bescheid, ob er in ISO-Latin-1 ("Bytes") oder UTF-8 ("Unicode") kodiert ist. Die Operatoren ({{C:substr}}, {{C:s///}}...) kümmern sich um den Rest. Dann kam 5.6.0 mit UTF-8 support ("unicode-support"); ich portierte ein riesiges Modul und freute mich daran. Daran, dass gar nichts funktioniert. Naja, es tat eigentlich alles, bis man auf die Idee kam, Umlaute oder etwas ähnliches einzusetzen. Damals hätte ich noch umsteigen können, aber so lernt man nichts. Also blieb ich bei Unicode, schrieb böse E-mails, weniger Patches und basierte meine Module auf bleedperl, dem aktuellen Perl-snapshot. Blut habe ich gelassen. Dass Perl nur "bytes" und "UTF-8" unterstützt, ist offiziell nur Zufall. Die interne Repräsentation von Zeichen sollte "geheim" sein - ich meine, das ist gefährlicher Unsinn, aber möglicherweise werden sich zukünftige Versionen von Perl nicht mehr so sehr auf UTF-8 vs. Bytes beschränken. Das zieht aber jede Menge Arbeit nach sich ("oh, die vielen Bugreports die wir bekommen werden wenn wir das ändern"), so dass mir die Gefahr recht gering erscheint. Wenn also jemand fragt: ich habe niemals behauptet, Perl würde intern irgendetwas Bestimmtes unterstützen. H2: Perl-5.7 Wenn man den richtigen Snapshot hat, läuft Perl-5.7 hervorragend. Der Unicode-Support ist gut, von einigen kleineren Problemen abgesehen (wer braucht {{C:tr///}}?). Ich werde mich im folgenden mit der Version 5.7-DEVEL7952 (ein älterer Snapshot) beschäftigen. Ich hoffe, dass viele bzw. die meisten Bugfixes in 5.6.1 einfließen. H1: Die Grundlagen H2: {{C:use utf8}} vs. {{C:use bytes}} Seit der Unicode-Einführung gibt es zwei neue Pragmas, {{C:use utf8}} und {{C:use bytes}}. Diese schalten {{nicht}} zwischen UTF-8- und Byte-Modus hin und her, sie erfüllen zwei grundsätzlich unterschiedliche Zwecke. H3: {{C:use bytes}} Das {{C:bytes}}-Pragma entscheidet während der Laufzeit darüber, welche {{Semantik}} die Perl-Operatoren haben. Grundsätzlich gibt es zwei mögliche Interpretationen für einen Skalar: Entweder enthält er Zeichen ({{C:no bytes}}) oder irgendwelchen Binärkram ({{C:use bytes}}). Normalerweise macht Perl intuitiv das richtige (behaupten wir einfach mal). {{C:use bytes}} ist notwendig, wenn man sicher gehen will, dass Perl definitiv alles als Bytestring behandelt. Wenn man z.B. schreibt: !block perl $s = chr(9729); !endblock Dann enthält $s drei Bytes, da sich das Zeichen "9729" nur mittels drei Bytes kodieren läßt. Konsequenterweise liefert {{C:length $s}} auch den Wert "1" - ein Zeichen. Manchmal will man aber unbedingt, dass da Bytes drin stehen. Muss so sein. Dann schreibt man z.B. !block perl $length = do { use bytes; length $s }; !endblock Das liefert in unserem Beispiel 3. Das Ganze ist allerdings weit weniger sinnvoll, als es zuerst erscheint: Wenn {{C:$s}} z.B. ein JPEG-Bild enthält, dann ist es völlig wurscht, ob es durch irgendeinen internen Schluckauf innerhalb von Perl mal in UTF-8 umgewandelt wird - die Länge in Zeichen bleibt immer gleich. Nur bei der Ausgabe bekommt man Probleme, aber auch da hilft einem die Länge in Bytes nichts - wenn Perl meint, es wären Bytes in unserem Skalar, stimmt das normale length. Wenn Perl meint, es wäre UTF-8 drin, stimmt es auch. Deshalb ist es fraglich, was genau ein {{C:use bytes}} eigentlich bedeutet - so ganz klar scheint es auch den perl5-porters nicht zu sein - man braucht es relativ selten. Meistens muss man es nur abschalten, um ganz sicher zu gehen, dass der aktuelle Snapshot auch spurt. Übrigens konvertiert Perl recht selten einen Skalar in UTF-8, solange man nicht irgendwo im Programm explizit mit sowas anfängt. Programme, die kein UTF-8 benutzen, sind also sicher. H3: {{C:use utf8}} Wozu könnte nun das {{C:use utf8}} gut sein? Nun ja, wer die Diskussion um die Einführung eines neuen Operators mitbekommen hat (z.B. den {{C:??}}-Operator, genannt "Huh?", der übrigens sehr sinnvoll ist...) weiß, dass solche Sachen nicht leichtgenommen werden. Hey, wenn der Quellcode in UTF-8 ist... könnte man ja Unicode-Zeichen als Operatoren nehmen - davon gibt's ja genug! Das ist aber nicht das Hauptargument dafür, schon den Quellcode in UTF-8 zu schreiben. Auch String-Konstanten könnten ja schön leserlich in UTF-8 sein. Oder in ganz anderen Zeichensätzen oder Encodings. Ein bisschen davon bringt uns ein {{C:use utf8}}. In dessen Gültigkeitsbereich erwartet Perl, dass der Quellcode selbst in UTF-8 verfasst wird. Ausserhalb davon (bzw. nach einem {{C:no utf8}}) erwartet Perl z.Zt. ISO-8859-1, bzw. gar nichts bestimmtes, es ist einfach nur undefiniert). {{C:use utf8}} wird möglicherweise der Default in zukünftigen Perl-Versionen. Ein kompliziertes Beispiel will ich auf Rücksicht auf unseren wackeren "Setzer" nicht bringen, der hat mit meinen Vorlagen bestimmt schon genug zu kämpfen, aber dennoch: !block perl use utf8; $s = "Er erwürgt mich!"; # <- da steht ein "ü" in UTF-8! print length($s),"\n$s\n"; !endblock Dieses Programmfragment gibt zuerst die Zahl 16 und danach in einer separaten Zeile 17 Bytes aus - das "ü" benötigt zwei Bytes. Streicht man das {{C:use utf8}} weg, bekommt man die Zahl 17 und danach 17 Bytes - das "ü" sind für Perl nun nur noch zwei beliebige 8-Bit-Zeichen, die zwar keinen Sinn ergeben, aber sowas ist Perl ziemlich egal. Wenn wir übrigens schonmal dabei sind: !block perl use utf8; $lücke = "voll"; !endblock Eine Variable (Funktion... Filehandle...) mit Umlauten oder noch schlimmeren Zeichen ist an sich nichts Besonderes (das ging über symbolische Referenz schon immer), aber mit C kann man jetzt endlich auch direkt im Quelltext UTF-8-Zeichen verwenden, vorausgesetzt, sie sind "Wort"-Zeichen im Sinne von Unicode. Ich sehe eine grosse Zukunft für den Obfuscated Perl Contest... H3: String-Konstanten und -Funktionen Mit einem {{C:use utf8}} bekommt man also Unicode in seine Skalare, aber nicht jeder hat einen Editor, der UTF-8 beherrscht, und selbst dann werden Dateien gerne mal konvertiert - wer hat wohl nicht einen Rechner zuhause, der unbedingt EBCDIC-DE benötigt.... Ein Weg, Unicode-Zeichen in sein Programm zu bringen, ist {{C:chr()}}. Wenn man bei {{C:chr()}} eine Zahl <128 übergibt, bekommt man ein ASCII-Zeichen. Bei >255 bekommt man UTF-8, und dazwischen - genau: Glückssache. Genaugenommen entscheidet dann ein etwaiges {{C:use utf8}}, ob man ein Byte oder ein UTF-8-Zeichen bekommt. Die {{C:ord()}}-Funktion funktioniert übrigens immer korrekt - solange Perl weiss, was in dem Skalar gespeichert ist. Notfalls muss man selbst dafür sorgen. Wer ganz sicher gehen will, kann mittels Backslash-Escape Unicode in Strings einbetten: !block perl $s = "Er erw\x{FC}rgt mich!"; !endblock Das erzeugt einen UTF-8-String, Länge 16, 17 Bytes lang. Immer. Zumindest in DEVEL7952 ;) Unsere Wolke könnte man so ausgeben: !block perl print "\x{2601}"; # 0x2601 == 9729 !endblock Aber es geht noch besser, mit dem {{C:\N}}-Escape kann man Zeichen auch per Namen ansprechen: !block perl use charnames ':full'; print "\N{CLOUD}"; print "\N{LATIN SMALL LETTER A}"; use charnames ':short'; print "\N{greek:sigma}"; !endblock Die muss man aber erst mit dem {{C:charnames}}-Pragma "importieren". Es gibt jede Menge Möglichkeiten, Zeichen nach Namen zu finden, inklusive der selbsterdachten - {{C:perldoc charnames}} gibt Auskunft. H2: Holzhammer Bevor ich zu den regulären Ausdrücken komme ("jaaaa"), muss ich nochmal Abschweifen ("neiiin"!). Perl macht nicht das, was es soll. Ob nie, manchmal oder immer, hängt vom Programm ab. Wie behilft man sich, wenn man doch so gerne UTF-8 nutzen würde, es aber irgendwie hakt? Häufiges Beispiel{{}}: "Mein String enthält Daten im Binärformat, aber irgendein Schwein hat es in UTF-8 umgewandelt. Wie gebe ich das denn jetzt aus?". Da gibt es mehrere Möglichkeiten, aber externe Hilfe (sprich: ein Modul) braucht man. Bei Perl-5.7 ist eines dabei, es nennt sich {{C:Encode}}. Leider habe ich schlechte Erfahrungen damit gemacht, und da sich die API sehr wahrscheinlich ändern wird, nehme ich im folgenden das ältere {{C:Convert::Scalar}}, dafür muss man leider den Umweg über CPAN machen, das macht sich aber durch eine größere Nähe zu den Bits & Bytes bezahlt. Betrachten wir mal dies: !block perl use Convert::Scalar ':utf8'; $x = big_complicated_function_that_might_return_utf8(...); utf8_downgrade $x; print $x; !endblock Egal, was in {{C:$x}} drinsteht - solange es sich in Bytes darstellen lässt, bekommen wir Bytes. Die Funktionen in {{C:Convert::Scalar}} verändern dabei das Argument direkt und geben es meistens zurück (jaja, {{C:utf8_downgrade}} ist die Ausnahme, es gibt einen Wahrheitswert zurück, der angibt, ob's geklappt hat), d.h. hinterher steht in {{C:$x}} ein Bytestring. Was passiert, wenn Zeichen >255 in {{C:$x}} stehen? Dann steigt {{utf8_downgrade}} mit einem Laufzeitfehler aus (Den kann man mit {{C:utf8_downgrade $skalar, 1}} umgehen um z.B. den Rückgabewert auszuwerten). Andersherum geht es auch: Wir haben einen Skalar (unbekannter Herkunft, d.h. unbekannter Kodierung) und möchten UTF-8 ausgeben (oder benötigen aus anderen Gründen UTF-8). Dafür gibt es {{C:utf8_upgrade}}: !block perl $x = ganz_komische_funktion(); print utf8_upgrade $x; !endblock Im Gegensatz zu {{C:utf8_downgrade}} kann das niemals schiefgehen, weshalb die Funktion günstigerweise eine Kopie des Skalars zurückliefert. Also{{}}: {{C:utf8_downgrade}} und {{C:utf8_upgrade}} benötigt man dann, wenn man sichergehen will, dass Perl einen Skalar in einer bestimmten Kodierung speichert. Eigentlich benötigt man sie dann, wenn der Sch**** (siehe auch: "Reguläre Ausdrücke" \N{SMILEY}) wieder nicht geht und man einfach {{will}}, dass das Programm endlich funktioniert. Das Herumwandeln der Kodierung (das tun Kodierungen besonders gerne nachts) ist meistens unproblematisch: Perl weiß immer, welche Kodierung verwendet wird und kann nötigenfalls automatisch umwandeln. Manchmal meint Perl aber, der Skalar wäre in einer bestimmten Kodierung, obwohl dies gar nicht der Fall ist (z.B. wenn wir einen Textstring aus einer UTF-8-Datei gelesen haben). Perl setzt die Kodierung entsprechend der Umgebung ({{utf8}}-Pragma, Mondphase, Laune...). Ein Beispiel: Holen wir einmal die aktuelle Mondphase aus einer SQL-Datenbank: !block perl use PApp::SQL; $phase = sql_fetch "select phase from mondphasen where tag = ?", $tag; !endblock Nun ist C<$phase> in UTF-8. Oder doch nicht? Jaja, es ist schon in UTF-8, aber Perl weiss das vielleicht noch nicht? Dafür gibt es {{C:utf8_on}}: !block perl $phase = utf8_on sql_fetch "select... !endblock Jetzt gibt es keine Fragen mehr: C setzt einfach das UTF-8-Flag, egal, ob es vorher gesetzt war oder nicht. Natürlich gibt es entsprechend auch ein C, es wird aber seltener eingesetzt. Warum? Nehmen wir mal an, wir würden die Phase in der Datenbank ändern: !block perl sql_exec "update mondphasen set phase = ? where tag = ?", utf8_upgrade $phase, $tag; !endblock Warum um Himmels willen nicht C oder C? Nun, nehmen wir einmal an, unsere Datenbank (+Perl-Interface!) verstünde UTF-8 (gibt es sowas?). Dann ist alles in Ordnung: wir lügen nicht, geben immer UTF-8 an die Datenbank, und unser C ist ein NOP. Wenn unsere Datenbank (oder das DBI-Interface) kein UTF-8 versteht, übergeben wir die Daten immer in UTF-8-Kodierung ("Dübel" kann in Perl 5 oder 6 Byte lang sein!), sie werden also {{normiert}}. Innerhalb der Datenbank geht meistens auch alles gut (sie hält unsere Strings dann eben für was anderes, aber dank der gutmütigen Eigenschaften von UTF-8 macht das selten Probleme). Und beim Angeln der Daten wird das UTF-8-Flag wieder gesetzt. Falls die Datenbank irgendwann mal UTF-8 beherscht, muss man alle Spalten nur mit dem Äquivalent von C behandeln und alles läuft weiter. Anderes Beispiel: C. Dieses Modul gibt, wie wir ja alle wissen, UTF-8 zurück. Auch in Perl5.005. Halt ohne UTF-8-Flag. Das bedeutet, dass je nachdem, in welcher Version XML::Parser vorhanden ist und unter welcher Perl-Version es übersetzt wurde (jaa!) manchmal das UTF-8-Flag gesetzt ist und manchmal nicht. Deshalb: C verwenden, wir wissen ja, es steckt UTF-8 drin. H3: Line Disciplines Eine ganz tolle Sache wird passieren: C usw. wird vollständig verschwinden. Das ist nicht toll? Ja, dafür bekommen wir die Line-Disciplines. Damit kann man z.B. sagen "STDIN ist ab jetzt in UTF-8" oder besser: "STDIN ist ab jetzt in ISO-2022-JP". Die Klassengesellschaft wird abgeschafft, alle Kodierungen sind gleich(er). Und meinen Quellcode möchte ich bitteschön auch in ISO-2022-JP (JP für Japan ;) kodieren können! Noch weiß niemand, wie das aussehen soll, und ich glaube, es wird noch ein bisschen dauern. Inzwischen wird das C-Modul einige Funktionen anbieten, mit denen man den Datentyp "Zeichen in Bytes" in UTF-8 umkodieren kann, also eine Art C/C für beliebige Zeichensätze. Aber ganz so weit sind wir noch nicht. H2: Reguläre Ausdrücke Wer Textverarbeitung betreibt, benötigt reguläre Ausdrucke, am besten die nicht-reguläre Variante in Perl ;) Wie andere Sprachen ohne auskommen, wird mir für immer ein Rätsel..., ehrm... wo war ich stehengeblieben? Reguläre Ausdrücke beherrschen UTF-8. Meistens jedenfalls. Je nachdem, ob sie unter C oder C kompiliert(!) wurden (siehe auch: "Mondphase"), beherrschen sie genau diese Variante. Das ist nicht schlimm, leider kodiert Perl die Strings vorher nicht um... Folgendes{{}}: !block perl sub escape_attr { local $_ = shift; s/(['<>&\x00-\x1f\x80-\x9f])/sprintf "&#%d;", ord($1)/ge; $_; } !endblock ist absolut {{tödlich}}!! Das klappt nur mit... tja, eben solchen Strings, die die gleiche Kodierung haben, mit der die Regex kompiliert wurde. Da hilft nur der Holzhammer: !block perl sub escape_attr { local $_ = shift; use utf8; utf8_upgrade $_; # jetzt ist es UTF-8 s/(['<>&\x00-\x1f\x80-\x9f])/sprintf "&#%d;", ord($1)/ge; utf8_on $_; # je nach Perl-Snapshot ist das hilfreich $_; } !endblock Im übrigen können da die lustigsten Effekte passieren. In manchen Versionen geht die zweite Zeile, die erste aber nicht: !block perl s/(.)/$1/g; # geht (manchmal) s/(.)/my $x = $1; $x/ge; # geht (meistens) !endblock Sie sehen den Unterschied nicht? Tja, Sie haben eben noch keine 4 Stunden lang daran herumdebugged. Aber das sind alte Geschichten, so etwas passiert dann {{doch}} seltener und ist dann ein Bug in Perl (in diesem Fall liegt es daran, dass C<$1> recht magisch ist und seinen Inhalt erst recht spät zugewiesen bekommt). Das Beispiel soll nur zeigen, dass man durchaus den Mut besitzen sollte, Perl eines Fehlers zu bezichtigen. Das kommt sonst nämlich sehr selten vor. H3: Erweiterungen innerhalb von regulären Ausdrücken Bis jetzt ging es eigentlich nur um die Grundlagen (bzw. wie man Fehler umgeht). Aber um Unicode parsen zu können, braucht man schon ein paar mehr Werkzeuge, als es frühere Perlen angeboten haben. Stürzen wir uns einmal auf Zeichenklassen. C<\W> kennt fast jeder. Ich benutze es dauernd, im festen Wissen, dass es eigentlich nicht ganz korrekt ist. Bei Unicode ist es sogar meistens ganz falsch, denn die Gruppe der "Wort-Zeichen" ist bei Unicode-Anwendungen größer. Oder einfach anders... Da die Zahl der einbuchstabigen Abkürzungen begrenzt ist (ein Problem, vor dem auch die POSIX-Zeichenklassen standen) hat man zwei neue Escapes eingeführt: C<\p{EIGENSCHAFT}> und C<\P{EIGENSCHAFT}>. Klein-p steht für ein einzelnes Zeichen in der benannten Eigenschaft, z.B. steht C<\p{IsWord}> für ein Wort-Zeichen (also in etwa das, was man sich normalerweise unter C<\W> vorstellt). Gross-P ist das Gegenteil (nicht-Eigenschaft). Die folgende Zeile sucht nach einem Bezeichner, der mit einem Buchstaben anfängt und danach aus alphanumerischen (inklusive "_") Zeichen besteht auf die {{kein}} "Freiraum" folgt. Es ist etwas an den Haaren herbeigezogen... !block perl $s =~ /\p{IsAlpha}[\p{IsAlnum}_]*(?=\P{IsSpace})/; !endblock Die Namen für die Zeichenklassen findet man übrigens nur im Camel, kann eigentlich nicht sein, aber ich habe nirgendwo etwas gefunden (vor allem nicht dort, wohin man in der Dokumentation verwiesen wird). Eine kleine Liste bekommt man mit C und C, ansonsten muss man sich direkt das C-Unterverzeichnis im Perl-Library-Verzeichnis ansehen. Oder den Unicode-Standard, wobei man aber raten muss, wie die entsprechende Klasse in Perl heißt. Oder was die Zeichenklasse macht. Ein weiteres, nützliches Escape-Zeichen ist C<\X>, das passt auf ein Unicode-Zeichen inklusive darauffolgender Akzente oder ähnlicher Zeichen (sogenannte "combining chars", C + (combining) C<~> == C<ñ>). H1: Ausblick Was wird sich noch tun? Nun, zum einen wird die Restriktion auf UTF-8/nicht-UTF-8 entschärft. Es gibt keinen Grund, {{ausschließlich}} UTF-8 zuzulassen. Wenn man schon jedes Unicode-Zeichen in Bezeichnern zulässt, dann sollte das auch in jeder Kodierung möglich sein. Ebenso sollte die interne Repräsentation nicht mehr so stark hervortreten, so dass man später nur noch zwischen "Bytes" und "Zeichen" unterscheidet. Wie das genau aussehen soll, ist mir nicht klar, es scheint mir sehr kompliziert. Das wichtigste sind die sog. "line disciplines", von denen man sich sehr viel Arbeitserleichterung erhoffen kann: Da die meisten Daten doch irgendwann über ein Filehandle gelesen (oder geschrieben) werden, kann man an dieser Stelle zweckmäßigerweise eine Konvertierung durchführen. Das funktioniert natürlich nicht bei "Dateien", auf denen Binär- und Textdaten gemischt werden (also fast alle, man denke z.B. an die Netzwerkverbindung zur Datenbank ;). Ja, liebe Unix-Freunde: C wird auch Unix treffen, erschlagen und nie wieder weiterziehen. A1: Links * RFC 2279: UTF-8, a transformation format of ISO 10646 * {{C:perldoc charnames}} - Zeichennamen * {{C:perldoc perlunicode}} - was geht alles NICHT? * C - Unicode Dateien * C, der Unicode-Standard