2. Zeichen (Characters)
Dieses Kapitel definiert die Zeichensätze, Kodierungsmechanismen und Verarbeitungsregeln, die in URIs verwendet werden.
Grundlagen der Zeichenkodierung
Die URI-Syntax bietet eine Methode zur Kodierung von Daten in eine Zeichenfolge, wahrscheinlich zum Zweck der Identifizierung einer Ressource.
Kodierungshierarchie:
Ressource → URI-Zeichen → Oktette → Übertragung/Speicherung
Zeichensatz: URIs basieren auf dem US-ASCII-Zeichensatz, bestehend aus Ziffern, Buchstaben und einigen grafischen Symbolen
2.1. Prozent-Kodierung (Percent-Encoding)
Zweck
Ein Prozent-Kodierungsmechanismus wird verwendet, um ein Datenoktett in einer Komponente darzustellen, wenn das diesem Oktett entsprechende Zeichen außerhalb der erlaubten Menge liegt oder als Trennzeichen verwendet wird.
Kodierungsformat
pct-encoded = "%" HEXDIG HEXDIG
Format: Eine Prozent-Kodierung besteht aus einem Prozentzeichen "%" gefolgt von zwei hexadezimalen Ziffern, die den numerischen Wert dieses Oktetts darstellen
Beispiele
| Zeichen | Binär | Hexadezimal | Prozent-Kodiert |
|---|---|---|---|
| Leerzeichen | 00100000 | 0x20 | %20 |
| ! | 00100001 | 0x21 | %21 |
| # | 00100011 | 0x23 | %23 |
| ä (deutsch) | - | 0xC3A4 | %C3%A4 |
Groß-/Kleinschreibungsregeln
Äquivalenz: Die Groß hexadezimalen Ziffern 'A' bis 'F' sind äquivalent zu den Kleinbuchstaben 'a' bis 'f'
Normalisierung: Zwei URIs, die sich nur in der Groß-/Kleinschreibung der hexadezimalen Ziffern in prozent-kodierten Oktetten unterscheiden, sind äquivalent
Empfehlung: URI-Produzenten und -Normalisierer sollten (SHOULD) Großbuchstaben für alle Prozent-Kodierungen verwenden
Empfohlen: %2F %3A %5B
Nicht empfohlen: %2f %3a %5b
2.2. Reservierte Zeichen (Reserved Characters)
Definition
URIs enthalten Komponenten und Subkomponenten, die durch Zeichen aus der "reservierten" Menge getrennt sind. Diese Zeichen werden "reserviert" genannt, weil sie als Trennzeichen definiert sein können (oder auch nicht).
Reservierter Zeichensatz
reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
Klassifizierung
Allgemeine Trennzeichen (gen-delims)
| Zeichen | Zweck | Beispiel |
|---|---|---|
| : | Trennt Schema und Autorität | http: |
| / | Pfad-Trennzeichen | /path/to/resource |
| ? | Abfrage-Trennzeichen | ?key=value |
| # | Fragment-Trennzeichen | #section |
| [ ] | IPv6-Adressgrenzen | [2001:db8::1] |
| @ | Benutzerinformations-Trennzeichen | user@host |
Unter-Trennzeichen (sub-delims)
| Zeichen | Häufige Verwendung |
|---|---|
| ! $ ' ( ) * | Subkomponententrennung in Pfad oder Abfrage |
| + | Alternative Leerzeichendarstellung |
| , | Listentrenner |
| ; | Parametertrenner |
| = | Schlüssel-Wert-Trenner |
| & | Abfrageparameter-Trenner |
Kodierungsregeln
Konfliktbehandlung: Wenn Daten für eine URI-Komponente mit dem Zweck eines reservierten Zeichens als Trennzeichen kollidieren, müssen (MUST) die kollidierenden Daten prozent-kodiert werden, bevor der URI gebildet wird
Beispiele:
Pfad mit "?"-Zeichen:
Original: /path/file?.txt
Kodiert: /path/file%3F.txt
Abfrage mit "&"-Zeichen:
Original: ?name=Tom&Jerry
Korrekt: ?name=Tom%26Jerry (wenn & kein Trennzeichen ist)
Oder: ?name=Tom&name=Jerry (wenn & ein Trennzeichen ist)
Äquivalenz
Wichtig: URIs, die sich im Ersetzen eines reservierten Zeichens durch sein entsprechendes prozent-kodiertes Oktett unterscheiden, sind NICHT äquivalent
http://example.com/path?key=value
http://example.com/path%3Fkey=value
Diese beiden URIs sind NICHT äquivalent
2.3. Nicht reservierte Zeichen (Unreserved Characters)
Definition
Zeichen, die in einem URI erlaubt sind, aber keinen reservierten Zweck haben, werden als nicht reserviert bezeichnet.
Nicht reservierter Zeichensatz
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
Enthält:
- ALPHA: Groß- und Kleinbuchstaben (A-Z, a-z)
- DIGIT: Dezimalziffern (0-9)
- -: Bindestrich
- .: Punkt
- _: Unterstrich
- ~: Tilde
Kodierungsregeln
Äquivalenz: URIs, die sich im Ersetzen eines nicht reservierten Zeichens durch sein entsprechendes prozent-kodiertes US-ASCII-Oktett unterscheiden, sind äquivalent
Normalisierung: Prozent-kodierte Oktette, die nicht reservierten Zeichen entsprechen, sollten (SHOULD) dekodiert werden
Äquivalente URIs:
http://example.com/~user
http://example.com/%7Euser
Normalisiert zu:
http://example.com/~user
Prozent-Kodierungsbereich
Sollte NICHT erstellt werden (SHOULD NOT):
- ALPHA:
%41-%5A(A-Z),%61-%7A(a-z) - DIGIT:
%30-%39(0-9) - Bindestrich:
%2D - Punkt:
%2E - Unterstrich:
%5F - Tilde:
%7E
Sollte dekodiert werden: Wenn diese Kodierungen in einem URI gefunden werden, sollten (SHOULD) Normalisierer sie in ihre entsprechenden nicht reservierten Zeichen dekodieren
2.4. Wann kodieren oder dekodieren (When to Encode or Decode)
Wann kodieren
URI-Produzenten:
- Bei der Erzeugung des URI müssen (MUST) nicht erlaubte Zeichen prozent-kodiert werden
- Reservierte Zeichen werden nur dann nicht kodiert gelassen, wenn sie als Trennzeichen verwendet werden
- Nicht reservierte Zeichen sollten nicht (SHOULD NOT) kodiert werden
Beispiele:
# Pfadkodierung
path = "/files/my document.pdf"
encoded = "/files/my%20document.pdf"
# Abfragekodierung
query = "?name=John Doe&age=30"
encoded = "?name=John%20Doe&age=30"
Wann dekodieren
URI-Konsumenten:
- Nach dem Parsen des URI, Komponenten nach Bedarf dekodieren
- Nicht vorzeitig dekodieren (kann URI-Struktur ändern)
- Jede Komponente nur einmal dekodieren
Gefährliches Beispiel:
Original: /path%2Fto%2Ffile
Vorzeitige Dekodierung: /path/to/file (Pfadstruktur geändert!)
Korrekt: Erst parsen, dann jedes Segment dekodieren
Segment 1: "path%2Fto%2Ffile" → Dekodieren → "path/to/file"
Doppelkodierungsproblem
Originaldaten: "100%"
Erste Kodierung: "100%25"
Falsche zweite Kodierung: "100%2525"
Beim Dekodieren:
"100%2525" → "100%25" → "100%"
2.5. Identifizierung von Daten (Identifying Data)
Zeichensätze und Kodierung
Zeichen vs. Oktett:
- URIs sind Zeichenfolgen
- Zeichen werden als Oktette für Übertragung/Speicherung kodiert
- UTF-8 ist die empfohlene Zeichenkodierung
Internationalisierte Ressourcenidentifikatoren (IRI)
IRI-Erweiterung: RFC 3987 definiert IRIs, die die Verwendung von Unicode-Zeichen erlauben
Konvertierung:
IRI: http://例え.jp/引き出し
↓ In UTF-8 kodieren und prozent-kodieren
URI: http://xn--r8jz45g.jp/%E5%BC%95%E3%81%8D%E5%87%BA%E3%81%97
Best Practices
URI-Produktion:
- Nicht-ASCII-Zeichen mit UTF-8 kodieren
- Resultierende Oktette prozent-kodieren
- Große hexadezimale Ziffern verwenden
- Nicht reservierte Zeichen nicht kodieren
URI-Konsum:
- Nach Komponente parsen
- Prozent-Kodierungen dekodieren
- Oktette mit UTF-8 interpretieren
- Ungültige Kodierungen behandeln
Zeichensatz-Schnellreferenz
Vollständige Zeichenklassifizierung
URI-Zeichen
├── Nicht reserviert (unreserved)
│ ├── ALPHA: A-Z, a-z
│ ├── DIGIT: 0-9
│ └── Symbole: - . _ ~
│
├── Reserviert (reserved)
│ ├── Allgemeine Trennzeichen (gen-delims): : / ? # [ ] @
│ └── Unter-Trennzeichen (sub-delims): ! $ & ' ( ) * + , ; =
│
└── Prozent-kodiert (pct-encoded): %HEXDIG HEXDIG
Kodierungsentscheidungsbaum
Zeichen muss im URI erscheinen?
├─ Ist nicht reserviertes Zeichen? → Direkt verwenden
├─ Ist reserviertes Zeichen?
│ ├─ Als Trennzeichen verwendet? → Direkt verwenden
│ └─ Als Daten verwendet? → Prozent-kodieren
└─ Anderes Zeichen? → Prozent-kodieren
Häufige Zeichenkodierungstabelle
| Zeichen | Zweck | Kodierung |
|---|---|---|
| Leerzeichen | Trennung | %20 oder + (in Abfrage) |
| ! | Unter-Trennzeichen | %21 (falls Kodierung nötig) |
| " | Anführungszeichen | %22 |
| # | Fragment-Trennzeichen | %23 (in Daten) |
| $ | Unter-Trennzeichen | %24 (falls Kodierung nötig) |
| % | Kodierungsmarker | %25 |
| & | Parametertrenner | %26 (in Daten) |
| ' | Unter-Trennzeichen | %27 (falls Kodierung nötig) |
| ( ) | Unter-Trennzeichen | %28 %29 |
| + | Leerzeichen/Unter-Trennzeichen | %2B (in Daten) |
| , | Listentrenner | %2C (falls Kodierung nötig) |
| / | Pfad-Trennzeichen | %2F (in Daten) |
| : | Schema-Trenner | %3A (in Daten) |
| ; | Parametertrenner | %3B (falls Kodierung nötig) |
| = | Schlüssel-Wert-Trenner | %3D (falls Kodierung nötig) |
| ? | Abfrage-Trennzeichen | %3F (in Daten) |
| @ | Benutzerinfo-Trenner | %40 (in Daten) |
| [ ] | IPv6-Grenzen | %5B %5D |
Implementierungsempfehlungen
Kodierungsimplementierung
def percent_encode(text, safe=''):
"""Text prozent-kodieren"""
result = []
for char in text:
if char in safe or is_unreserved(char):
result.append(char)
else:
# UTF-8-kodieren und prozent-kodieren
for byte in char.encode('utf-8'):
result.append(f'%{byte:02X}')
return ''.join(result)
def is_unreserved(char):
"""Prüfen, ob Zeichen nicht reserviert ist"""
return (char.isalnum() or
char in '-._~')
Dekodierungsimplementierung
def percent_decode(text):
"""Text prozent-dekodieren"""
result = bytearray()
i = 0
while i < len(text):
if text[i] == '%' and i + 2 < len(text):
try:
byte = int(text[i+1:i+3], 16)
result.append(byte)
i += 3
except ValueError:
result.extend(text[i].encode('utf-8'))
i += 1
else:
result.extend(text[i].encode('utf-8'))
i += 1
return result.decode('utf-8', errors='replace')
Nächstes Kapitel: 3. Syntaxkomponenten (Syntax Components) - Strukturelle Komponenten von URIs