- Jede Ebene geht von `U+XY0000` bis `U+XYFFFF`, kann also $2^{16}=65\;534$ Zeichen enthalten.
- Vorgesehen sind bisher 17 Ebenen `XY=00` bis `XY=10`, also der Wertebereich von `U+0000` bis `U+10FFFF`.
- Damit sind maximal 21 Bits pro Zeichen nötig.
- Die Gesamtzahl der damit möglichen Codepoints ist etwas kleiner als 0x10FFFF, da aus technischen Gründen gewisse Bereiche nicht verwendet werden. Sie beträgt etwa 1.1 Millionen, es ist also noch viel Platz.
_Unicode transformation formats_ legen fest, wie eine Folge von Codepoints als eine Folge von Bytes dargestellt wird.
Da die Codepoints unterschiedlich lang sind, kann man sie nicht einfach hintereinander schreiben. Wo hört einer auf und fängt der nächste an?
- __UTF-32__: Das einfachste, aber auch speicheraufwändigste, ist, sie alle auf gleiche Länge zu bringen. Jeder Codepoint wird in 4 Bytes = 32 Bit kodiert.
- Bei __UTF-16__ wird ein Codepoint entweder mit 2 Bytes oder mit 4 Bytes dargestellt.
- Bei __UTF-8__ wird ein Codepoint mit 1,2,3 oder 4 Bytes dargestellt.
- __UTF-8__ ist das Format mit der höchsten Verbreitung. Es wird auch von Julia verwendet.
### UTF-8
- Für jeden Codepoint werden 1, 2, 3 oder 4 volle Bytes verwendet.
- Bei einer Codierung mit variabler Länge muss man erkennen können, welche Bytefolgen zusammengehören:
- Ein Byte der Form 0xxxxxxx steht für einen ASCII-Codepoint der Länge 1.
- Ein Byte der Form 110xxxxx startet einen 2-Byte-Code.
- Ein Byte der Form 1110xxxx startet einen 3-Byte-Code.
- Ein Byte der Form 11110xxx startet einen 4-Byte-Code.
- Alle weiteren Bytes eines 2-,3- oder 4-Byte-Codes haben die Form 10xxxxxx.
- Damit ist der Platz, der für den Codepoint zur Verfügung steht (Anzahl der x):
- Ein-Byte-Code: 7 Bits
- Zwei-Byte-Code: 5 + 6 = 11 Bits
- Drei-Byte-Code: 4 + 6 + 6 = 16 Bits
- Vier-Byte-Code: 3 + 6 + 6 + 6 = 21 Bits
- Damit ist jeder ASCII-Text automatisch auch ein korrekt codierter UTF-8-Text.
- Sollten die bisher für Unicode festgelegten 17 Ebenen (= 21 Bit = 1.1 Mill. mögliche Zeichen) mal erweitert werden, dann wird UTF-8 auf 5- und 6-Byte-Codes erweitert.
replace("π ist irrational.", "ist" => "ist angeblich")
```
## Indizierung von Strings
Strings sind nicht mutierbar aber indizierbar. Dabei gibt es ein paar Besonderheiten.
- Der Index nummeriert die Bytes des Strings.
- Bei einem nicht-ASCII-String sind nicht alle Indizes gültig, denn
- ein gültiger Index adressiert immer ein Unicode-Zeichen.
Unser Beispielstring:
```{julia}
str
```
Das erste Zeichen
```{julia}
str[1]
```
Dieses Zeichen ist in UTF8-Kodierung 4 Bytes lang. Damit sind 2,3 und 4 ungültige Indizes.
```{julia}
str[2]
```
Erst das 5. Byte ist ein neues Zeichen:
```{julia}
str[5]
```
Auch bei der Adressierung von Substrings müssen Anfang und Ende jeweils gültige Indizes sein, d.h., der Endindex muss ebenfalls das erste Byte eines Zeichens indizieren und dieses Zeichen ist das letzte des Teilstrings.
```{julia}
str[1:7]
```
Die Funktion `eachindex()` liefert einen Iterator über die gültigen Indizes:
```{julia}
for i in eachindex(str)
c = str[i]
println("$i: $c")
end
```
Wie üblich macht collect() aus einem Iterator einen Vektor.
```{julia}
collect(eachindex(str))
```
Die Funktion `nextind()` liefert den nächsten gültigen Index.
```{julia}
@show nextind(str, 1) nextind(str, 2);
```
Warum verwendet Julia einen Byte-Index und keinen Zeichenindex? Der Hauptgrund dürfte die Effizienz der Indizierung sein.
- In einem langen String, z.B. einem Buchtext, ist die Stelle `s[123455]` mit einem Byte-Index schnell zu finden.
- Ein Zeichen-Index müsste in der UTF-8-Codierung den ganzen String durchlaufen, um das n-te Zeichen zu finden, da die Zeichen 1,2,3 oder 4 Bytes lang sein können.
Einige Funktionen liefern Indizes oder Ranges als Resultat. Sie liefern immer gültige Indizes:
```{julia}
findfirst('l', str)
```
```{julia}
findfirst("Hel", str)
```
```{julia}
str2 = "αβγδϵ"^3
```
```{julia}
n = findfirst('γ', str2)
```
So kann man ab dem nächsten nach `n=5` gültigen Index weitersuchen: