Tips and Tricks: Typing Unicode

I found this on netzwolf.info:

You can enter arbitrary Unicode characters (more precisely code points) in X11 on Linux, if you know their Hex-Code:

  • Press Shift-Ctrl (keep them pressed)
  • Press also the letter u
  • Release the Ctrl-Key
  • Release the u-key
  • Keep the Shift-key pressed
  • Enter the Hex-Code of the Code point with the number of hex digits needed
  • Release the shift key

Let’s try with the Cyrillic Alphabet, more precisely with its Unicode Block:

  • Ѐ U+0400
  • Ё U+0401
  • Ђ U+0402
  • Љ U+0409
  • А U+0410
  • Б U+0411
  • В U+0412
  • Г U+0413
  • Д U+0414

Not very fast, but it works quite well for a few characters. Just open the table in one window and use this key sequence in another one.

For frequently used characters it is a good idea to remap the keyboard with xmodmap.

Share Button

Some thoughts about String equality

Of course Strings are today in some way Unicode. In this article we assume code points as the building blocks of Strings. That means for example in the Java-world, that we are talking about one code point being comprised of one Java character for typical European languages, using Latin, Greek or Cyrillic alphabets including extensions to support all languages typically using these alphabets, for example. But when moving to Asian languages, a code point can also consist of two Java characters and there are Strings that are illegal from Unicode perspective, because they contain characters that should be combined in a way that cannot be combined properly. So here we assume, that Strings consist of sequences of bytes or two-byte characters or whatever encoding that properly express a sequence of code points. There are many interesting issues when dealing with some Asian languages that we will not cover here today.

Now there are a lot of possibilities to create Strings, that look the same, but are actually different. We are not talking about „0“ and „O“ or „1“ and „l“ and „I“ that might look similar in some fonts, but should not look similar, because we actually depend on their distinctness, even on their visual distinctness. Unfortunately we have the bad habit of using traditional typewriter fonts, that make it hard to distinguish these, for source code, where it would be so crucial. But for today, we just assume that we always look hard enough to solve this issue.

The classical example of what looks the same is whitespace. We have ordinary space “ “ and no break space “ „, that are meant to look exactly the same, but to expose a slightly different behavior. There are tons of possibilities to create exactly the same look with different combinations of whitespace. But this is kind of a special case, because in terms of semantics often carries little information and we want to disregard it to some extent when comparing strings. Typical examples are stripping of leading and trailing whitespace of the string or of the lines contained within it and replacing tabulators with the number of spaces that would be equivalent. Or even to replace any amount of adjacent whitespace within a line by a single space. Again, handling of different whitespace code points might require different rules, so it is good to be careful in not putting to much logic and it is better to rely on a library to at least apply exactly the same rules in equivalent situations.

Another example that we actually might know is that certain characters look the same or almost the same in the Cyrillic, Greek and Latin alphabets. I try to give an idea of the meaning of the Greek and Cyrillic characters, but they depend on the language, the dialect and even the word, the word form or the actual occurrence of the letter in the word…

LatinCyrillicGreekmeaning of Cyrillic Lettermeaning of Greek letter
AАAlike Latinlike Latin
BВBlike Latin VBeta (like V in new Greek)
CСlike Latin S
EЕElike LatinEpsilon (like Latin E)
ГHlike Latin GGamma (like Latin G)
HНΗlike Latin NEta (like Latin I in new Greek)
JЈSerbian Ј, like German J
KКΚlike LatinKappa (like Latin K)
MМΜlike LatinMu (like Latin M)
NΝNu (like Latin N)
OОΟlike LatinOmikron (like Latin O)
PРΡlike Latin RRho (like Latin R)
ПΠlike Latin PPi (like Latin P)
TТΤlike LatinTau (like Latin T)
ФΦlike Latin FPhi (like Latin F)
XХΧlike German CHChi (like German CH)
YУΥlike Latin UUpsilon (like Latin U)
ZΖZeta (like German Z)
IІΙUkrainian IIota (like Latin I)

In this case we usually want the characters to look the same or at least very similar, because that is how to correctly display them, but we do want them to be different when comparing strings.

While these examples are kind of obvious, there is another one that we tend to ignore, but that will eventually catch us. There are so called combining characters, that should actually be named „combining code points“, but here we go. That means that we can put them after a letter and they will combine to form a letter with diacritical marks. A typical example is the letter „U“ that can be combined with two dots “ ̈ ̈“ to form an „Ü“, which looks the same as the „Ü“ that is composed of one code point. It is meant to look the same, but it also has the same meaning, at least for most purposes. What we see is the Glyph. We see the difference when we prefix each code point with a minus or a space: „Ü“ -> „-U-̈“ or “ U ̈“, while the second one is transformed like this: „Ü“ -> „-Ü“ or “ Ü“, as we would expect.

While the way to express the Glyph in such a way with two code points is not very well known and thus not very common, we actually see it already today when we look at Wikipedia articles. In some languages, where the pronunciations is ambiguous, it can be made clear by putting an accent mark on one vowel, as for example Кириллица, which puts an accent mark on the term in the beginning of the article like this: „Кири́ллица“. Since in Cyrillic Alphabet accent marks are unfortunately not used in normal writing, it comes in handy that the combining accent also works with cyrillic letter. When putting minus-signs between the code points it looks like this: „К-и-р-и-́-л-л-и-ц-а“ or with spaces like this: „К и р и ́ л л и ц а“. So Strings that we encounter in our programs will contain these combining characters in the future. While we can prohibit them, it is better to embrace this and it is actually not too hard, if we use decent libraries. Java has the Normalizer class in its built in library, that can convert to one or the other convention of expressing such glyphs and then allowing comparison in the way that we actually mean.

Unfortunately issues like semantic lengths of strings or semantic positions become even harder than they already are after moving from characters to code points. And we can be sure that Unicode has still more to offer to complicate things, if we dig deeper. The typical answer that we get on most web sites that talk about these issues is something like: „The length of strings and positions within strings are surprisingly irrelevant to most programs.“

In the end of the day, jobs that have been trivial in the past are now becoming a big deal and we need to learn to think of comparison, length, position, regular expressions, sorting and all kinds of string functionality with bytes, characters, code points and glyphs in mind.

What can our current libraries already do for us, what are we missing in them, considering different programming languages, databases, text files and network transmission?

Links

Share Button

Unicode, UTF-8, UTF-16, ISO-8859-1: Why is it so difficult?

Deutsch

Since about 20 years we have been kept busy with the change to Unicode.

Why is it so difficult?

The most important problem is that it is hard to tell how the content of a file is to be interpreted. We do have some hacks that often allow recognizing this:
The suffix is helpful for common and well defined file types, for example .jpg or .png. In other cases the content of the file is analyzed and something like the following is found in the beginning of the file:

#!/usr/bin/ruby

From this it can be deduced that the file should be executed with ruby, more precisely with the ruby implementation that is found under /usr/bin/ruby. If it should be the ruby that comes first in the path, something like

#!/usr/bin/env ruby

could be used instead. When using MS-Windows, this works as well, when using cygwin and cygwin’s Ruby, but not with native Win32-Ruby or Win64-Ruby.

The next thing is quite annoying. Which encoding is used for the file? It can be a useful agreement to assume UTF-8 or ISO-8859-1 or ISO-8859-15, but as soon as one team member forgets to configure the editor appropriately, a mess can be expected, because files appear that mix UTF-8 and ISO-8859-1 or other encodings, leading to obscure errors that are often hard to find and hard to fix.

Maybe it was a mistake when C and Unix and libc were defined and developed to understand files just as byte sequences without any meta information about the content. This more or less defined how current operating systems like Linux and MS-Windows deal with it.

They did not really have a choice, although they did both provide facilities that could theoretically be used to carry such information, but since almost no software uses them and there are no well known and established standards, this is not helpful today. In the internet mime headers have proved to be useful for email and web pages and some other content. This allows the recipient of the communication to know how to interpret the content.

It would have been good to have such meta-information also for files, allowing files to be renamed to anything with any suffix without loosing the readability. But in the seventies, when Unix and C and libc where initially created, such requirements were much less obvious and it was part of the beauty to have a very simple concept of an I/O-stream universally applicable to devices, files, keyboard input and some other ways of I/O. Also MS-Windows has probably been developed in C and has inherited this flaw. It has been tried to keep MS-Windows runnable on FAT-file-systems, which made it hard to benefit from the feature of NTFS of having multiple streams in a file, so the second stream could be used for the meta information. But as a matter of fact suffixes are still used and text files are analyzed for guessing the encoding and magic bytes in the beginning of binary files are used to assume a certain type.

Off course some text formats like XML have ways of writing the encoding within the content. That requires iterating through several assumptions in order to read up to that encoding information, which is not as bad as it sounds, because usually only a few encodings have to be tried in order to find that out. It is a little bit annoying to deal with this when reading XML from a network connection and not from a file, which requires some smart caching mechanism.

This is most dangerous with UTF-8 and ISO-8859-x (x=1,2,3,….), which are easy to mix up. The lower 128 characters are the same and the vast majority of the content consists of these characters for many languages. So it is easy to combine two files with different encodings and not recognizing that until the file is already somewhat in use and has undergone several conversion attempts to „fix“ the problem. Eventually this can lead to byte sequences that are not allowed in the encoding. Since spoken languages are usually quite redundant, it usually is possible to really fix such mistakes, but it can become quite expensive for large amounts of text. For UTF-16 this is easier because files have to start with FFFE or FEFF (two bytes in hex-notation), so it is relatively reliable to tell that a file is utf-16 with a certain endianness. There is even such a magic sequence of three bytes to mark utf-8, but it is not known by many people, not supported by the majority of the software and not at all commonly used. Often we have to explicitly remove these three marker bytes in order to avoid confusing software processing the file.

In the MS-Windows-world things are even more annoying because the whole system is working with modern encodings, but this black CMD-windows is still using CP-850 or CP-437, which contain almost the same characters as ISO-8859-1, but in different positions. So an „ä“ might be displayed as a sigma-character, for example. This incompatibility within the same system does have its disadvantages. In theory there should be ways to fix this by changing some settings in the registry, but actually almost nobody has done that and messing with the registry is not exactly risk-less.

Links

Share Button

GNU-Emacs und Unicode

Heute sollte man Text-Dateien bevorzugt in Unicode erstellen und speichern. Natürlich braucht man nur englische Texte, deshalb reicht ISO-646 (ASCII) aus, aber ein paar Umlaute kommen doch noch rein, allein wegen Eigennamen und so kann man ISO-8859-1 oder ISO-8859-15 nehmen und hat die Umlaute auch dabei. Praktisch mit demselben Aufwand kann man stattdessen UTF-8 verwenden. Das erlaubt es, die Umlaute zu haben, aber auch alle anderen Unicode-Zeichen. Und die seltenen Umlaute sind zwei Bytes statt einem groß, was in aller Regel vernachlässigbar ist. Eine andere Frage ist es aber, wenn man z.B. Russisch, Griechisch, Japanisch oder Chinesisch schreibt. utf-8 führt dazu, dass die griechischen und russischen Buchstaben mindestens zwei Bytes brauchen und die chinesischen und japanischen noch mehr. Bei diesen Sprachen ist zugegebenermaßen der Anreiz, eine Codierung zu verwenden, die auf diese Sprache zugeschnitten ist, größer, weil man so die Textdateien um Faktor 1.5 oder 2 kleiner machen kann. Weiß jemand, wie das heute praktiziert wird? In welcher Codierung speichert man üblicherweise Textdateien bei Sprache, die nicht auf lateinischen Buchstaben basieren?

Nun hat GNU-Emacs leider vor vielen Jahren seine eigene Idee statt Unicode entwickeln wollen, wie man die Zeichen der verschiedenen Sprachen codiert. Wer das noch weiß, wird vielleicht dem ganzen Werkzeug misstrauen, aber das ist nicht nötig.
Man kann eine einzelne Datei als Textdatei in utf-8 markieren, indem man in der ersten Zeilen einen Kommentar hat, der etwa so aussieht:

// -*- coding: utf-8-with-signature-unix -*-
// -*- coding: utf-8-with-signature -*-
// -*- coding: utf-8-unix -*-
// -*- coding: utf-8 -*-

Ab dann wird die Datei als Unicode gespeichert und auch beim nächsten öffnen interpretiert.
Das „-unix“ erzwingt einen Zeilenwechsel nur aus „ctrl-J“ (LF), statt „ctrl-M ctrl-J“ (CR LF), was in der Regel besser funktioniert, wenn man sowohl auf Win64/Win32 als auch auf Linux/Unix-Plattformen unterwegs ist.
Das -with-signature führt dazu, dass am Anfang der Datei eine „Signatur“ aus drei Bytes eingefügt wird, die ausdrückt, dass die Datei utf-8 ist. Leider wird diese Signatur nicht von allen Werkzeugen verstanden, aber wenn sie verstanden wird, ist das eigentlich der richtige Ansatz, weil man so wirklich utf-8 erkennen kann, ohne die ganze Datei vorher zu lesen.

Das läßt sich auch pro Endung festlegen, wenn man in .emacs so etwas schreibt:

(defvar utf8-suffix-regex nil "describes suffixes of files that are always utf8")

(setq utf8-suffix-regex "\\.\\(cs\\|scala\\|java\\|groovy\\)$")

(defun choose-encoding-by-suffix ()
  "Choose the encoding based on suffix"
  (interactive)
  (when (and (stringp buffer-file-name)
             (string-match utf8-suffix-regex buffer-file-name))
    (set-buffer-file-coding-system 'utf-8-unix nil t)))

(add-hook 'find-file-hook 'choose-encoding-by-suffix)

Wenn bei diesen impliziten Konvertierungen etwas schiefgeht, z.B. weil iso-8859-1 nach utf-8-Konvertierung zweimal statt einmal gelaufen ist, dann hilft recode. Man kann im Emacs die geöffnete Datei mit recode konvertieren:
Ctrl-X h ESC 1 ESC | recode utf8..latin1
Es empfiehlt sich, vorher eine Sicherungskopie anzulegen.

Dieselben Fragestellungen tauchen mit anderen Editoren und Entwicklungsumgebungen auch auf. In Eclipse und Netbeans kann man die Codierung von Dateien nach Endung, Projekt und auch für einzelne Dateien festlegen. Sicher wissen die vi-Spezialisten gut Bescheid, wie es mit vi geht.

Entscheidend ist, dass man sich bewusst für eine Codierung entscheidet. In Sprachen mit lateinischer Schrift dürfte das fast immer utf-8 sein, wenn man nicht „Altlasten“ hat. Das lässt sich mit geeigneten Editoren in den Griff bekommen.

Links

Share Button

Unicode, UTF-8, UTF-16, ISO-8859-1: Warum ist das so schwierig?

English

Seit etwa 20 Jahren schlagen wir uns mit der Umstellung auf Unicode herum.

Warum ist das so schwierig?

Das größte Problem ist, dass man Dateien nur sehr begrenzt ansieht, wie ihr Inhalt zu interpretieren ist. Wir haben letztlich ein paar Tricks, mit denen man es oft erkennen kann:
Die Endungen funktionieren für häufige und gut definierte Dateitypen, z.B. .jpg oder .png recht gut. In anderen Fällen wird der Inhalt der Datei untersucht und zum Beispiel am Anfang der Datei so etwas wie

#!/usr/bin/ruby

gefunden, woraus geschlossen werden kann, dass das mit ruby ausgeführt werden soll und zwar mit dem Ruby, das unter /usr/bin/ruby steht. Wenn man sich lieber nicht festlegen will und das Ruby haben will, das zuerst im Pfad ( $PATH ) kommt, dann kann man stattdessen

#!/usr/bin/env ruby

verwenden. Das geht leider unter MS-Windows nur unter cygwin, wenn man das cygwin-Ruby verwendet, nicht aber mit dem nativen Win32-Ruby (oder Win64-Ruby).

Nun kommt aber der nächste Schritt und der ist einfach ärgerlich. Welches „encoding“ wird für diese Datei verwendet? Man kann sich auf UTF-8 oder ISO-8859-1 einigen, aber sobald einer im Team vergisst, seinen Editor entsprechend zu konfigurieren, ist Durcheinander abzusehen, weil dann Dateien entstehen, die UTF-8 und ISO-8859-1 (oder noch andere Encodings) miteinander mischen, was dann irgendwann zu obskuren Fehlern führt.

Es war ein großer Fehler, dass bei der Entwicklung von C, Unix und vor allem der Linux folgt diesen Vorgaben. Aber auch in der MS-Windows-Welt hat man die Betriebssysteme wahrscheinlich in C entwickelt und dabei diese Eigenschaften oder deren Fehlen geerbt. Ich weiß nicht, bis wann man versucht hat, MS-Windows-NT/2000/XP/Vista/7/8… noch auf FAT-Dateisystemen lauffähig zu halten, dabei hätte NTFS mit den multiplen Streams pro Datei eine Werkzeug geschaffen, mit dem man so einen Mime-Typ im zweiten Stream und den eigentlichen Inhalt im ersten Stream speichern könnte. Was aber fehlt ist ein allgemein anerkanntes Regelwerk, das die Nutzung des zweiten Streams für Typinformationen festlegt Aber man verwendet weiterhin Endungen, hofft auf gutes Glück bei Textdateien und analysiert magic-bytes innerhalb der Dateien, um den Typ der Datei und das Encoding zu raten. Linux hat Attribute, in denen man solche Information ablegen kann, aber das bringt nur etwas, wenn es ein Standard ist, den „alle“ kennen und der von jeder Software, die davon betroffen ist, eingehalten wird.

Natürlich haben XML und HTML die Möglichkeit, das Encoding innerhalb der Datei zu definieren. Dummerweise muss man aber das Encoding der Datei schon kennen, um die Zeilen zu lesen, wo drinsteht, welches Encoding die Datei hat. Das ist nicht so schlimm, denn letztlich steht diese Information jeweils am Anfang der Datei und man kann ein paar Encodings durchprobieren, und jeweils unter dieser Annahme anfangen, die Datei zu lesen, bis man es richtig weiß. UTF-16 erkennt man an den beiden Markerbytes am Anfang und dann kann man mit der Annahme UTF-16 lesen, bis man das Encoding, das nun UTF-16 sein muss findet. Andernfalls kann man mit der Annahme, dass es UTF-8 ist, anfangen und muss dann auf das, was man gefunden hat, umstellen. Wenn kein Encoding angegeben ist, ist UTF-8 sowieso der Defaultwert.

Am gefährlichsten ist es, UTF-8 und ISO-8859-1 (oder ähnliche Encodings) zu verwechseln. Da die unteren 128 Zeichen bei beiden gleich sind und zumindest im deutschen Sprachraum doch die überwältigende Mehrheit von Text-Inhalten darstellen, sticht das Problem nicht gleich ins Auge, sondern schleicht sich eher ein, wenn man nicht sauber arbeitet und Dateien mit verschiedenen Encodings zusammenkopiert oder die Dateien den falschen Konversionen aussetzt. Nun werden aber die Umlaute in UTF-8 durch zwei Zeichen codiert, in ISO-8859-1 durch eines. Beim Lesen der Datei unter der falschen Annahme bekommt man also irgendwann mal Zeichenfolgen, die in dem Encoding eigentlich gar nicht vorkommen dürften. Bei UTF-16 ist das einfacher, weil die Dateien dort jeweils mit FFFE oder FEFF anfangen, so dass man einigermaßen sicher UTF-16 an sich und die Bytefolge (niedriges zuerst oder hohes zuerst) erkennen kann. Es gäbe auch eine drei Byte lange Markierung für UTF-8. Obwohl das jede Software verstehen sollte, ist man in der Praxis meistens gezwungen, diese Byte-Sequenz zu entfernen, weil sie die meiste Software verwirrt, zu fehlerhaften Verhalten bringt oder gar zum Absturz bringt.

In der MS-Windows-Welt kommt noch als weiteres Ärgernis hinzu, dass zwar das ganze System mit modernen Encoding arbeiten kann, aber diese schwarzen CMD-Fenster kommen immer noch mit CP-850 oder CP-437 hoch, enthalten also in etwa dieselben Zeichen wie ISO-8859-1, aber an anderen Positionen. Da bekommt man dann schon einmal ein Sigma-Zeichen statt einem „ä“ zu sehen. Diese Incompatibilität innerhalb desselben Systems bringt natürlich Nachteile mit sich.

Links

Share Button