Ich setzte mich daran, ein Bisschen Code in C++ zu schreiben, um mit Polynomen zu rechnen. Zu meinem eigenen Nutzen wollte ich eine Funktion schreiben, die die als Koeffizientvektoren kodierte Polynomen in eineme Terminal schön abbilden könne. Natürlich hatte ich die Absicht, die speziale Unicode-Zeichen ⁰¹²³⁴⁵⁶⁷⁸⁹
dazu zu benützen, weil x⁵
sehr schöner als x^5
aussieht. Anfänglich entwickelte ich eine Funktion, die jede Ziffer von 0 bis 9 in sein hochgestelltes Gegenstück von Unicode beziehungsweise übersetzen könnte.
char digit_superscript(int d) {
// some stuff here...
}
Aber das klappt nicht. Jedes mit UTF8 codierte Unicode-Zeichen kann aus bis vier Bytes bestehen. Ein char
kann nur ein einziges Byte enthalten und deshalb musste ich stattdessen ein string
zurückgeben.
string digit_superscript(int d) {
// some stuff here...
}
Am einfachsten (und wahrscheinlich am schnellsten) könnte man zehn hartkodierte Fälle auflisten und das angemessene Unicode-Zeichen in jedem Fall zurückgeben. Solcher Code wäre doch sehr unangenehm und repetitiv und es ist mir egal, wie schell meine Polynomen gedruckt werden. Mir fiel eine alte Methode ein, die mir gute Dienste bei der Bearbeitung von ASCII-Zeichen geleistet hat: um den n-te Buchstabe vom Alphabet zu holen, kann man einfach $n$ mit dem Zeichen 'a'
versetzen, weil die Buchstaben a..z
konsekutiv sind. Vielleicht könnte man die Hochzahl $d$ von einem mit $d$ versetzten Zeichen ⁰
erreichen.
Dem Unicode-Zeichen ⁰
entspricht das Codepoint U+2070
, das in UTF8 mit den Bytes e2 81 b0
kodiert wird. Ich probierte es aus:
string digit_superscript(int d) {
string num = "\xe2\x81\xb0";
num.at(2) += d;
return num;
}
Dann versuchte ich, die Ziffer ab null bis neun abzubilden, um diese Funktion zu prüfen:
int main() {
for (int i = 0; i < 10; i++)
cout << digit_superscript(i);
cout << "\n";
}
Die Ausgabe: ⁰ⁱ⁴⁵⁶⁷⁸⁹
. Verdammt nochmal!
So ist es: die Unicode-Hochzahlen sind gar nicht konsekutiv. Das hochgestellte Nullzeichen hat das Codepoint U+2070
aber dem Codepoint U+2071
entspricht das hochstellte "i"-Zeichen ⁱ
. Damit nicht genug, die Codepoints U+2072
und U+2073
entsprechen gar keinen Zeichen und sie sind "für spätere Nutzung reserviert". Glücklicherweise bewohnen die Hochzahlen ⁴⁵⁶⁷⁸⁹
die konsekutive Codepoints von U+2074
bis U+2079
.
Was ist denn mit ¹²³
los? Laut Wikipedia sind sie von der Codierung ISO-8859-1, die eine einbytige ASCII erweiternde Codierung mit nur diesen drei Hochzahlen und keinen von den anderen ist, übergenommen. Um diese Kodierung zu beachten hat Unicode die ISO-8859-1-Zeichen ihre beziehungsweise Codepoints in seinem Block Latin-1 behalten gelassen, aber diese Entscheidung hat eine peinliche Folge: die Hochzahlen ¹²³
sind ungefähr 8000 Codepoints von ihren Geschwistern getrennt. Mindestens hat ⁰
den Sonderling ⁱ
als Gesellschaft. Sie sind irgendwie verwandt, nicht wahr? Weil sie beide so hochgeschriebene... Dinge sind?
Es kommt noch dicker: innerhalb ISO-8859-1 sind ¹²³
auch nicht konsekutiv. Die Zeichen ²³
sind U+00B2
und U+00B3
aber ¹
ist U+00B9
. Na, ausgezeichnet.
Zurück zum Programmieren: Für die Ziffern ⁰⁴⁵⁶⁷⁸⁹
benutzte ich die Versetzens-Technik aber für die Ziffern ¹²³
waren abgesonderte Spezialfälle nötig.
string digit_superscript(int d) {
switch (d) {
case 1:
return "\u00b9";
case 2:
return "\u00b2";
case 3:
return "\u00b3";
default:
string num = "\xe2\x81\xb0";
num.at(2) += d;
return num;
}
}
Wie schrecklich...