Zum Hauptinhalt springen

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

ZeichenBinärHexadezimalProzent-Kodiert
Leerzeichen001000000x20%20
!001000010x21%21
#001000110x23%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)

ZeichenZweckBeispiel
:Trennt Schema und Autoritäthttp:
/Pfad-Trennzeichen/path/to/resource
?Abfrage-Trennzeichen?key=value
#Fragment-Trennzeichen#section
[ ]IPv6-Adressgrenzen[2001:db8::1]
@Benutzerinformations-Trennzeichenuser@host

Unter-Trennzeichen (sub-delims)

ZeichenHä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:

  1. Bei der Erzeugung des URI müssen (MUST) nicht erlaubte Zeichen prozent-kodiert werden
  2. Reservierte Zeichen werden nur dann nicht kodiert gelassen, wenn sie als Trennzeichen verwendet werden
  3. 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:

  1. Nach dem Parsen des URI, Komponenten nach Bedarf dekodieren
  2. Nicht vorzeitig dekodieren (kann URI-Struktur ändern)
  3. 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:

  1. Nicht-ASCII-Zeichen mit UTF-8 kodieren
  2. Resultierende Oktette prozent-kodieren
  3. Große hexadezimale Ziffern verwenden
  4. Nicht reservierte Zeichen nicht kodieren

URI-Konsum:

  1. Nach Komponente parsen
  2. Prozent-Kodierungen dekodieren
  3. Oktette mit UTF-8 interpretieren
  4. 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

ZeichenZweckKodierung
LeerzeichenTrennung%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