Konzept: Zeichenverlust ist nicht Mojibake
11-Der deklarierte Zeichensatz ist eine Behauptung beschreibt den einen Schaden auf der Zeichensatzschicht: Die Deklaration in MSH-18 und die tatsächliche Kodierung fallen auseinander, und aus „Müller” wird „Müller”. Diese Seite beschreibt den zweiten, der dieselbe Schicht betrifft, im Ticket denselben Namen trägt („Umlautproblem”) und sich in jeder anderen Hinsicht gegenteilig verhält.
Eine v2-Nachricht ist dreifach kodiert
Wer sie liest, baut drei Schichten nacheinander ab. Jede ist woanders deklariert, jede kann für sich brechen, und keine merkt etwas vom Bruch der anderen.
| # | Schicht | Wo deklariert | Was sie regelt | Bruchbild |
|---|---|---|---|---|
| 1 | Zeichen ← Bytes | MSH-18 (Tabelle 0211), Default ASCII | welche Bytefolge welches Zeichen bedeutet | Mojibake, Zeichenverlust |
| 2 | Struktur ← Zeichen | MSH-1 / MSH-2, positionell gelesen | welche Zeichen Struktur bedeuten statt Text | Feld- und Komponentenversatz |
| 3 | Text ← Struktur | § 2.7 Escape-Sequenzen | wie ein Strukturzeichen doch Text sein darf, und wie ein Zeichen reist, das der Zeichensatz nicht kennt | Datenverlust im Wert |
Die Reihenfolge ist zwingend: Schicht 2 ist erst lesbar, wenn Schicht 1 aufgelöst ist, Schicht 3 erst nach Schicht 2. Ein Defekt auf Schicht 1 ist für alle darüberliegenden Prüfungen unsichtbar — sie arbeiten bereits mit dem Ergebnis.
Die zwei Schäden auf Schicht 1
| Verfälschung (Mojibake) | Verlust (Transkodierung) | |
|---|---|---|
| Ursache | Deklaration ≠ tatsächliche Kodierung | Zeichen existiert im Zielzeichensatz nicht |
| Bytes | alle vorhanden, nur falsch gedeutet | nicht mehr vorhanden |
| Ergebnis | Müller | Wisniewska statt Wiśniewska |
| Rekonstruierbar aus der Nachricht? | ja, solange niemand normalisiert | nein, nie |
| Im Ziel als Fehler erkennbar? | ja, sofort — sieht kaputt aus | nein — sieht aus wie ein Name |
| Wer meldet es? | jeder, der draufschaut | niemand, oft jahrelang |
Mojibake ist laut und heilbar. Zeichenverlust ist leise und endgültig.
Der Grund steht in der vorletzten Zeile: Das Ergebnis eines Verlusts ist ein gültiger, plausibler Wert. Keine Prüfung kann einem Namen ansehen, dass er einmal anders geschrieben war.
Drei Wege, auf denen ein Zeichen verschwindet — alle drei sind Voreinstellungen realer Konvertierungswerkzeuge:
- Transliteration (
ś→s) — der gefährlichste Fall, weil das Ergebnis plausibel ist. - Ersatzzeichen (
ś→?) — immerhin sichtbar. - Abbruch oder Trunkierung — sichtbar, aber leicht als Längenproblem fehlgedeutet.
Der Zeichenvorrat ist ein Vertragsgegenstand
Die Zeile „Zeichensatz: ISO 8859-1” in einem Schnittstellenkonzept sagt mehr zu, als ihr Verfasser meist geprüft hat. Die Abdeckung lässt sich ausrechnen:
| Zeichensatz | ä ö ü ß | polnisch ś ć ń ł ż ź ą ę | türkisch ğ ı İ ş | é è à ç ñ |
|---|---|---|---|---|
| 8859/1 (Latin-1) | ja | nein | nein | ja |
| 8859/15 (Latin-9) | ja | nein | nein | ja |
| 8859/2 (Latin-2) | ja | ja | nur ş | nur é ç |
| 8859/9 (Latin-5) | ja | nein | ja | ja |
Es gibt keinen Ein-Byte-Zeichensatz, der den Namensvorrat eines mitteleuropäischen Krankenhauses abdeckt. Deutsch plus Polnisch geht nur mit Latin-2, Deutsch plus Türkisch nur mit Latin-5, beides zusammen mit keinem von beiden.
Wer 8859/1 vereinbart, vereinbart damit implizit, dass ein Teil der Patientennamen nicht übertragbar ist. Was mit diesen Namen geschieht, steht in den seltensten Konzepten — und die Voreinstellung der Strecke entscheidet es dann still.
MSH-18 — drei Eigenschaften, die selten mitgelesen werden
- Optional, Default ASCII. Fehlt das Feld, gilt der 7-Bit-Vorrat (ISO IR6). Jede Nachricht mit Umlaut und leerem
MSH-18liegt damit außerhalb ihrer eigenen Deklaration — was in der Praxis niemanden stört und die Deklaration endgültig zur Formsache macht. - Wiederholbar (Sequenz 18,
ID, optional, RP = Y). Zweite und folgende Vorkommen benennen zusätzliche Zeichensätze, zwischen denen die Nachricht per Escape-Sequenz umschaltet. HL7 v2 stammt aus einer Zeit, in der ein Zeichensatz nicht genügte und Unicode keine Selbstverständlichkeit war. - Tabelle 0211 listet Zeichensätze, keine Sprachen. Geläufig sind
ASCII,8859/1–8859/9,8859/15, ostasiatische Sätze und — im heutigen Tabellenstand —UNICODE UTF-8(UNICODEgilt als abgekündigt). Der Tabellenstand ist versionsabhängig; vor einer Zusage im versionsrichtigen Anhang nachschlagen.
Escape-Sequenzen haben zwei verschiedene Aufgaben
§ 2.7 definiert einen abgeschlossenen Satz; das Escape-Zeichen selbst steht in MSH-2 und ist nicht fest verdrahtet.
| Sequenz | Bedeutung |
|---|---|
\F\ \S\ \T\ \R\ \E\ | field / component / subcomponent / repetition separator, escape character |
\H\ \N\ | start highlighting, normal text |
\Xdddd...\ | hexadecimal data |
\Zdddd...\ | locally defined escape sequence |
\Cxxyy\ | single-byte character set escape sequence |
\Mxxyyzz\ | multi-byte character set escape sequence |
„No escape sequence may contain a nested escape sequence.”
Aufgabe A — ein Strukturzeichen als Text transportieren. Eine Adresse „Hauptstr. 5 & 7” muss als Hauptstr. 5 \T\ 7 übertragen werden. Unterbleibt das, entsteht keine ungültige Nachricht, sondern eine wohlgeformte mit einer Subkomponente mehr. Kein Parser meldet etwas.
Aufgabe B — ein Zeichen transportieren, das der Zeichensatz nicht kennt. Dafür sind \Xdddd...\ (rohe Bytes in Hexpaaren) und die Umschaltsequenzen \Cxxyy\ / \Mxxyyzz\ gedacht, die auf ISO-IR-Repertoires zeigen (\C2842\ ASCII, \C2D41\ Latin Alphabet 1). Das ist der Grund, warum MSH-18 wiederholbar ist. In der Praxis unterstützt das kaum eine Installation; wer es einsetzt, verlagert das Problem in die Empfängerimplementierung. Der tragfähige Weg für Aufgabe B ist heute ein Zeichensatz, der den Vorrat abdeckt — also UTF-8.
Warum nichts davon auffällt
| Prüfung | prüft | findet einen Zeichenverlust? |
|---|---|---|
| Parser / Syntax | Trennzeichen, Segmentaufbau | nein |
| Schema / Datentyp | ist der Wert ein gültiges ST? | nein |
| Konformitätsprofil | Optionalität, Kardinalität, Wertevorräte | nein — Namen haben keinen Wertevorrat |
| ACK-Vertrag | Annahme, Verarbeitung | nein — AA, zu Recht |
| Fachliche Plausibilisierung | Bezug, Ordnung, Wertebereiche | nein — der Wert ist plausibel |
Dazu eine Falle in der Beweisführung, die den Fall regelmäßig um Wochen verlängert:
Ein Protokolleintrag ist immer das Ergebnis des vorangegangenen Schritts und die Absicht des nächsten. Welches von beidem er ist, entscheidet die Frage, die man ihm stellt.
Ein Kommunikationsserver hält Nachrichten intern als Zeichenketten und protokolliert aus dieser Darstellung; serialisiert wird erst danach. Wer sein Protokoll fragt „was habe ich empfangen?”, bekommt eine wahre Antwort. Wer es fragt „was habe ich ausgeliefert?”, bekommt dieselbe Antwort — und sie ist falsch. Der Nachweis für diese Fehlerklasse führt deshalb über die Bytes beider Streckenabschnitte, für denselben Fall, an der Systemgrenze abgegriffen. Nicht über das Log der Quelle, nicht über das des Ziels, nicht über die Anzeige.
Ein Defekt, der zwischen zwei Nachrichten wohnt
Die übliche Frage „auf welcher Ebene sitzt der Defekt — Wert, Feld, Segment, Anordnung, Bezugsdokument?” hat hier kein Objekt:
- Die beim Ziel eingehende Nachricht ist auf jeder Ebene einwandfrei: gültiger Wert, richtiges Feld, richtiges Segment, richtige Anordnung, Bezugsdokument eingehalten. Auch
MSH-18stimmt dort mit den Bytes überein — die Nachricht ist in sich vollkommen konsistent. - Die von der Quelle abgeschickte Nachricht ebenso.
- Es sind zwei verschiedene Nachrichten; der Defekt existiert nur in ihrer Differenz.
Die Ebenenleiter verortet Aussagen. Was hier defekt ist, ist keine Aussage, sondern eine Handlung — die Serialisierung. Handlungen stehen auf keiner Sprosse.
Praktische Folge, und der Grund, warum solche Fälle im Ticketsystem im Kreis laufen: Jeder Beteiligte kann seine Unschuld an seiner Nachricht belegen — und hat damit recht.
Prüffrage, die die Ebene Wert von einem Vergleich trennt:
Wogegen wäre dieser Wert falsch? Gegen einen Wertevorrat, ein Format oder einen Typ → dann ist es die Sprosse Wert. Nur gegen einen anderen Wert in einer anderen Nachricht → dann ist es keine Sprosse, sondern ein Vergleich.
Einordnung: Kategorie 6, und warum
Nach dem Raster in Die sechs Fehlerkategorien ist der Zeichenverlust Kategorie 6 (unterhalb des Vertrags).
- Bedingung 1 — Regelverstoß auf ungeprüfter Schicht: erfüllt. Die Zeichensatzschicht wird von keiner Prüfung des Zielsystems berührt, und eine Konvertierung, die Information vernichtet, ist von keiner Regel gedeckt — § 2.7 und die Wiederholbarkeit von
MSH-18stellen für genau diesen Fall Mechanismen bereit. - Bedingung 2 — die Information kommt nie an: erfüllt. Das Zeichen erreicht das Ziel in keiner Form; es ist vor dem Absenden vernichtet worden.
Der verbreitete Einwand gegen Bedingung 2 lautet: „Es kommt doch etwas an.” Er beruht auf einer Verwechslung:
Kategorie 6 ist keine Aussage über die Nachricht, sondern über eine Information. Eine Nachricht kann vollständig ankommen und trotzdem eine Information tragen, die nie abgeschickt wurde.
Abgrenzung gegen 4 (Mapping-Fehler) — die nächstliegende Alternative, weil eine Zeichensatzkonvertierung wörtlich eine Abbildung von A nach B ist und beide Endpunkte konform arbeiten:
Bei 4 ist die Information am Zielpunkt noch vorhanden, nur falsch abgebildet; bei 6 ist sie nicht mehr vorhanden. Operativer Test: Kann eine Korrektur allein beim Empfänger den Fall aus der vorliegenden Nachricht heilen? Ja → höchstens 4. Nein → 6.
Dieselbe Linie trennt auch die beiden Schäden dieser Seite: Mojibake ist im Ziel heilbar (4), Zeichenverlust nicht (6).
Abgrenzung gegen 5 (ungewollte Aussage): Bei 5 kommt die Aussage vollständig an und wird richtig verstanden — falsch ist ihr Inhalt. Bei 6 ist richtig, was ankommt, es ist nur nicht alles. Kurzform: Bei 5 ist die Aussage vollständig und falsch. Bei 6 ist sie richtig und unvollständig — und die Unvollständigkeit ist am Ziel nicht feststellbar.
Der zweite Befund. Wo ein Schnittstellenkonzept einen Zielzeichensatz vorgibt und zum Umgang mit nicht darstellbaren Zeichen schweigt, liegt daneben ein eigenständiger Befund der Kategorie 3: Die Vereinbarung sagt dazu nichts, also muss jemand auf der Strecke wählen. Er ist nicht die Ursache, sondern der Ermöglicher — und er ist der Grund, warum die Voreinstellung eines Produkts jahrelang eine Vertragslücke ausfüllen kann, ohne dass jemand sie unterschrieben hat.
Ein Kommunikationsserver ist kein Kabel. Er ist ein Verarbeitungsschritt mit eigener Konfiguration, eigenem Hersteller und eigenem Verantwortlichen — und er kommt in den meisten Schnittstellenkonzepten als Partei überhaupt nicht vor.
Daraus folgt der Adressat der Reparatur: weder Sender noch Empfänger, sondern die Strecke dazwischen und das Papier, das sie regelt.
Beispiel (synthetisch)
Nachname Wiśniewska, ein Streckenabschnitt in UTF-8, der folgende in ISO 8859-1:
Abschnitt 1, MSH-18 = UNICODE UTF-8
PID|1||100781^^^NS-A^MR||Wiśniewska^Anna^^^^^L||...
Bytes von PID-5.1.1: 57 69 C5 9B 6E 69 65 77 73 6B 61
Abschnitt 2, MSH-18 = 8859/1
PID|1||100781^^^NS-A^MR||Wisniewska^Anna^^^^^L||...
Bytes von PID-5.1.1: 57 69 73 6E 69 65 77 73 6B 61
In der zweiten Bytefolge steht kein defektes Byte, sondern ein 73 — der Buchstabe s. Aus Sicht jedes Empfängers ist das die Wahrheit über diesen Patienten.
Zum Kontrast derselbe Weg mit Müller:
UTF-8 : 4D C3 BC 6C 6C 65 72
Latin-1 : 4D FC 6C 6C 65 72 ← verlustfrei, denn ü existiert in Latin-1
Der Umlaut überlebt, das ś nicht. Ein Testset mit Müller und Groß prüft deshalb ausschließlich die Verfälschung und übersieht den Verlust vollständig.
Regel für Testdaten: Ein Testset muss mindestens ein Zeichen enthalten, das der vereinbarte Zeichensatz nicht kennt. Sonst ist diese Fehlerklasse im Test grundsätzlich unerreichbar.
Vier Änderungen und was sie wirklich tun
Der Fall taugt als Muster dafür, wie weit Reparatur, Sofortmaßnahme und Nachweis auseinanderliegen. Angenommen, ein Zielsystem zeigt transliterierte Namen:
| Änderung | Wirkung | Klasse | Setzt sie an der Ursache an? |
|---|---|---|---|
Zielsystem liest eingehende Bytes unabhängig von MSH-18 als UTF-8 | Symptom bleibt; die bisher funktionierenden Fälle brechen neu (FC ist kein gültiges UTF-8-Byte) | wirkungslos und zusätzlich schädlich — richtige Schicht, falsche Stelle der Strecke | nein |
| Strecke lehnt nicht darstellbare Inhalte ab, statt zu ersetzen | Symptom bleibt, aber der Fall scheitert sichtbar statt still | keine Reparatur, sondern Umwandlung eines stillen Fehlers in einen lauten | nein — und trotzdem die richtige Sofortmaßnahme |
| Zeichensatz der Strecke und des Vertrags auf UTF-8 | Symptom verschwindet für neue Nachrichten; Bestand bleibt | wirksam | ja — der Zeichenvorrat der Quelle wird gleichgültig |
| Strecke protokolliert die ausgehenden Bytes statt der internen Darstellung | ändert nichts am Defekt, macht ihn aber nachweisbar | wirkungslos als Reparatur, wirksam als Nachweis | nein, zielt auch nicht darauf |
Operative Folge: Ablehnen sofort, Zeichensatz als Reparatur, Ausgangsprotokoll als Nachweis — und das Umstellen des Empfängers auf keinen Fall. Drei Dinge nacheinander, nicht drei Alternativen.
Und die Einschränkung, die jede Ersetzungsprobe an dieser Fehlerklasse hat:
Eine Ersetzungsprobe rechnet vorwärts. Ein bereits transliterierter Bestand ist aus dem Zielsystem heraus nicht rekonstruierbar, weil keine Nachricht, die es je erhalten hat, das Zeichen enthielt. Der einzige Weg zum Bestand führt zurück zur Quelle — Neuversand oder Abzug.
Transfer
Ein Zeichenverlust erzeugt keinen ungültigen Wert und keinen fehlenden Datensatz. Er erzeugt einen Bestand, dessen Namensvorrat systematisch ärmer ist als die Wirklichkeit — und zwar in genau die Richtung, die mit Herkunft korreliert. Wer Datensätze über Namen verknüpft, verliert überproportional dieselben Gruppen; wer auf solchen Beständen auswertet, misst eine Eigenschaft eines Zeichensatzes von 1987 und hält sie für einen Befund.
Nach dem Kahn-Rahmen ist der Defekt in keinem der beiden Bestände messbar. Der Quellbestand ist konform, vollständig und plausibel; der Zielbestand ebenso — ein transliterierter Name ist ein gültiger, vollständiger, plausibler Name. Weder Conformance noch Completeness noch Plausibility schlagen an, in keiner ihrer Ausprägungen. Das ist die schärfste Fassung der Rahmengrenze: Kahn misst Bestände, nicht Strecken — und hier gehen beide Seiten leer aus, weil der Defekt zwischen ihnen sitzt.
Messbar wird er trotzdem, und mit einer einzigen Zahl:
Zeichenvorrats-Histogramm der Quelle gegen das der Senke. Anteil der Datensätze mit mindestens einem Zeichen außerhalb des vereinbarten Zeichensatzes, beidseitig gezählt. Steht links 0,8 % und rechts 0,0 %, ist der Befund fertig — ohne dass ein Einzelfall angesehen wurde.
Das ist eine reine Validation-Messung im Sinne des Rahmens; keine Verification findet sie, weil auf beiden Seiten alles konform ist. Für jede Bestandsmigration — Systemwechsel, Zusammenlegung, Archivübernahme — kostet sie eine Stunde und ist der billigste Beweis, den man in einem solchen Projekt führen kann.
FHIR entschärft die Schicht: Die Serialisierungen sind UTF-8, es gibt kein Äquivalent zu MSH-18, über das man verhandeln könnte. Was bleibt, ist die Konvertierung an der Systemgrenze — und die Tatsache, dass FHIR den Schaden erbt, statt ihn zu erzeugen. Ein seit Jahren transliterierter Namensbestand erfüllt nach der Migration jede Konformitätsprüfung, jedes Must-Support und jede Kardinalität. Mit falschen Namen.
Fragen an die Kunden-IT
- Welchen Zeichenvorrat müssen wir über diese Strecke tragen — welche Zeichen kommen in Ihren Patientenstammdaten tatsächlich vor? (Nicht die Deklaration erfragen, sondern den Vorrat. Die Antwort „nur deutsche Umlaute” ist am Bestand prüfbar und meistens falsch.)
- Was tut die Strecke mit einem Zeichen, das im Zielzeichensatz nicht existiert: ersetzen, ablehnen, abbrechen? Wo ist das konfiguriert, und wer hat es entschieden?
- Protokolliert der Kommunikationsserver seine interne Darstellung oder die ausgehenden Bytes?
- Enthält das Testset ein Zeichen außerhalb des vereinbarten Zeichensatzes?
- Wie viele Datensätze im Quellbestand tragen ein Zeichen außerhalb des vereinbarten Zeichensatzes — und wie viele im Zielbestand?
Prüffrage an die eigene Fragenliste, bevor sie rausgeht: Kann ich die Antwort selbst herstellen — durch Messen, Mitschneiden oder Nachlesen? Dann ist es keine Frage an die Gegenseite, sondern eine Aufgabe für mich.
Lektüre & Belege
- HL7 v2.5.1, Kapitel 2, § 2.7 — Escape-Sequenzen, Verschachtelungsverbot, § 2.7.5 Hexform,
\Cxxyy\/\Mxxyyzz\mit ISO-IR-Beispielen: hl7.eu ch02 - HL7 v2.5.1, Segmentbild MSH — Sequenz 18
Character Set,ID, optional, RP = Y, Item 00692, Tabelle 0211; Default ASCII/ISO IR6. Gegengelesen an hl7.eu/refactored segMSH (Kardinalität[0..*]). - Tabelle 0211 Alternate Character Sets — Werteliste: hl7.eu/refactored tab0211. Belegvorbehalt: Das ist der heutige Tabellenstand.
UNICODE UTF-16/UTF-32wurden nachweislich später aufgenommen; obUNICODE UTF-8bereits im Stand von v2.5.1 enthalten war, ist hier nicht belegt und vor einer Zusage im versionsrichtigen Anhang nachzuschlagen. - Belegvorbehalt: Was ein Empfänger mit einer ihm unbekannten Escape-Sequenz tun soll, ist in § 2.7 nicht gefunden worden. Das ist ein Recherchestand, keine Aussage über den Standard.
- Zeichenabdeckung der 8859-Sätze und alle Bytefolgen dieser Seite: gerechnet, nicht zitiert — gegen die Kodierungstabellen selbst geprüft.
- Querverweise: 11-Der deklarierte Zeichensatz ist eine Behauptung · 01-Die Trennzeichenhierarchie und warum sie fast immer leise bricht · 07-Framing entscheidet, was eine Nachricht ist · 14-Der Identifier ist ein Paar · Die sechs Fehlerkategorien · Das Kahn-Framework