Skip to content
Zurück zum Blog
Tutorials

UTF-8-BOM entfernen: JSON-Parse-Fehler und CSV in Excel

Eine UTF-8-BOM lässt JSON.parse an einer scheinbar perfekten Datei scheitern. So finden und entfernen Sie die unsichtbaren Bytes EF BB BF, und so erkennen Sie, wann Excel sie braucht.

14 Min. Lesezeit

UTF-8-BOM: JSON-Parse-Fehler und CSV-Probleme in Excel beheben

Hinter einem JSON-Parse-Fehler durch eine UTF-8-BOM stecken drei Bytes, die Sie nicht sehen können. Die Datei öffnet sich sauber in Ihrem Editor, cat gibt genau das aus, was Sie erwarten, Ihr Linter ist zufrieden, und JSON.parse wirft trotzdem beim allerersten Zeichen.

Gemessen auf node v25.8.2 sieht der Fehler so aus:

SyntaxError: Unexpected token '', "{"a":1}" is not valid JSON

Was Ihr Terminal zwischen diesen Anführungszeichen gezeichnet hat, ist ein einziges Zeichen: U+FEFF, gespeichert als die Bytes EF BB BF. Striktes JSON hat dafür keinen Platz. Ein Parser erwartet an Position 0 ein {, ein [, eine Ziffer, ein Anführungszeichen oder Leerraum, und U+FEFF ist nichts davon.

Wenn Sie bereits wissen, dass es eine BOM ist, wählen Sie die Seite, die Sie kontrollieren:

Wo Sie etwas ändern könnenDie Lösung
Node, beim Lesen einer DateiJSON.parse(raw.replace(/^/, ''))
Python, beim Lesen einer Dateiopen(path, encoding='utf-8-sig')
Die Datei auf der Festplattetail -c +4 data.json > clean.json

Der Rest dieser Seite ist für die Fälle, in denen das nicht reicht: für einen Fehler, der nur wie eine BOM aussieht, für die Quelle, die sie immer wieder neu einfügt, und für das eine Format, in dem gerade das Entfernen der Fehler ist. Was eine BOM überhaupt ist und ob eine neue Datei eine haben sollte, deckt der UTF-8- und UTF-16-Encoding-Guide ab. Diese Seite geht davon aus, dass Ihre bereits etwas kaputtgemacht hat.

Alle Messungen weiter unten stammen von node v25.8.2 und Python 3.14.5.

1. Was Ihr Fehler ausschließt, bevor Sie die BOM verdächtigen

Die meisten, die nach einem JSON-Fehler an Position 0 suchen, haben gar keine BOM. Vier verschiedene Probleme erzeugen eine Meldung derselben Form, und ein Blick auf das zitierte Zeichen trennt sie voneinander. Das sind die wörtlichen Zeichenketten, die V8 ausgibt:

FehlertextWas es tatsächlich istNächster Schritt
Unexpected token '', "{"a":1}" is not valid JSONUTF-8-BOM an Byte 0Abschnitt 2
Unexpected token '<', "<!DOCTYPE "... is not valid JSONDie Antwort war HTML: eine Fehlerseite, eine Login-Weiterleitung, ein Proxy-HinweisRohen Body und Statuscode loggen
Unexpected end of JSON inputDer Body war leerStatuscode und Content-Length prüfen
"undefined" is not valid JSONSie haben JSON.parse eine Variable übergeben, die nie zugewiesen wurdeDen Aufrufer korrigieren

Die Regel ist kurz genug zum Auswendiglernen. Lesen Sie das Zeichen innerhalb der einfachen Anführungszeichen. Ein < heißt, Sie haben HTML bekommen. Ein Kästchen, eine Lücke oder ein Fragezeichen, das sich nicht markieren lässt, heißt U+FEFF. Gar kein zitiertes Zeichen heißt, es gab von vornherein keine Eingabe.

Der alte und der neue Wortlaut

Suchergebnisse zu json parse unexpected token position 0 beziehen sich meist auf eine ältere V8-Meldung:

SyntaxError: Unexpected token in JSON at position 0

Diese Formulierung nannte den Offset und verschwieg das Zeichen. Die heutige macht das Gegenteil: Sie zeigt das Zeichen und einen Ausschnitt der Eingabe. Das hilft mehr, heißt aber auch, dass die Seite, auf der Sie landen, womöglich eine andere Laufzeitumgebung beschreibt als Ihre. Nennt Ihr Fehler weiterhin eine Position statt eines Zeichens, läuft bei Ihnen eine ältere Engine, und die Diagnose unten bleibt dieselbe.

2. In zehn Sekunden bestätigen, dass es eine BOM ist

Vier Prüfungen, grob nach Geschwindigkeit sortiert. Jede davon reicht allein aus.

Schauen Sie sich die ersten drei Bytes an.

$ hexdump -C data.json | head -1
00000000  ef bb bf 7b 22 61 22 3a  31 7d                    |...{"a":1}|

ef bb bf vor dem 7b ({) ist die BOM. Die ... in der ASCII-Spalte rechts sind das Eingeständnis von hexdump, dass es nichts Druckbares anzuzeigen hat.

Fragen Sie file. Es sagt es direkt und ändert dabei sogar seine Meinung über den Dateityp:

$ file data.json
data.json: Unicode text, UTF-8 (with BOM) text, with no line terminators

$ file clean.json
clean.json: JSON data

Prüfen Sie den ersten Codepunkt in Node.

const fs = require('fs');
const raw = fs.readFileSync('data.json', 'utf8');
console.log(raw.charCodeAt(0) === 0xFEFF);   // true

Lesen Sie die Statusleiste des Editors. VS Code zeigt unten rechts UTF-8 with BOM an, und ein Klick darauf bietet Save with encoding an. Dieses Label erklärt, warum die Datei in Ordnung aussah: Ihr Editor wusste Bescheid und hat es nur nicht laut gesagt.

Für einen Blick auf Byte-Ebene bei etwas, das Sie lokal nicht dumpen können, fügen Sie es in den Base64-Kodierer und -Dekodierer ein. Eine UTF-8-BOM am Anfang einer Nutzlast ergibt immer eine Zeichenkette, die mit 77u/ beginnt, und in einer Logzeile erkennen Sie sie genau daran.

3. Woher Ihre BOM kommt

Die BOM aus einer Datei zu entfernen, die ein Build-Schritt stündlich neu erzeugt, ist eine Lösung mit einer Stunde Haltbarkeit. Die üblichen Verursacher:

  • Excels Speichern unter → CSV UTF-8. Das ist Absicht und kein Fehler. Abschnitt 7 erklärt, warum.
  • Notepad und andere Windows-Editoren, die UTF-8 mit BOM als eigene Speicheroption anbieten, manchmal sogar als Vorgabe.
  • VS Code, wenn files.encoding auf utf8bom steht, entweder in Ihren Benutzereinstellungen oder eingecheckt in .vscode/settings.json, wo niemand nachsieht.
  • Shell-Umleitung in PowerShell. > und Out-File schreiben in manchen PowerShell-Versionen standardmäßig eine BOM, und die Vorgabe unterscheidet sich zwischen der reinen Windows-Linie 5.x und der plattformübergreifenden Linie 6/7. Verlassen Sie sich hier nicht auf Ihr Gedächtnis: Schreiben Sie eine Datei und prüfen Sie ihre ersten drei Bytes mit den Befehlen aus Abschnitt 2.
  • Selbstgebauter Export-Code. Jeder Writer, der einen UTF-8-Encoder erzeugt, ohne anzugeben, ob eine Signatur geschrieben werden soll, erbt die Vorgabe des jeweiligen Frameworks, und die Frameworks haben sich nicht alle für dasselbe entschieden. Alte .NET- und alte Java-Exportpfade fallen dabei am häufigsten auf.
  • Datenbank- und BI-Exportwerkzeuge, die oft eine BOM mitliefern, weil ihr Hauptabnehmer eine Tabellenkalkulation ist.

Kommt die Datei von einem Partner oder Anbieter und können Sie den Erzeuger nicht ändern, springen Sie zu Abschnitt 4 und entfernen die BOM beim Lesen. Stammt sie aus Ihrem eigenen Repository, ist Abschnitt 9 die dauerhafte Antwort.

4. Die Lösung in JavaScript und Node

Hier ballt sich die Verwirrung, denn das JavaScript-Ökosystem hat keine einheitliche BOM-Politik. Es hat mehrere, und sie widersprechen einander. Dieselbe Datei, dieselbe Laufzeitumgebung, gemessen auf node v25.8.2:

APIBOM-VerhaltenAnschließendes JSON.parse
fetchres.json()entfernterfolgreich
fs.readFileSync(f, 'utf8')behaltenschlägt fehl
new TextDecoder() (Vorgabe)entfernterfolgreich
new TextDecoder('utf-8', { ignoreBOM: true })behaltenschlägt fehl
require('./data.json')entferntentfällt, bereits geparst
import(..., { with: { type: 'json' } })entferntentfällt, bereits geparst

Aus dieser Tabelle folgen zwei Dinge, und beide kosten regelmäßig ganze Nachmittage.

ignoreBOM tut das Gegenteil von dem, was der Name sagt

ignoreBOM: true heißt nicht „ignoriere die BOM“. Es heißt „ignoriere die Sonderbedeutung der BOM und behalte sie als gewöhnliches Zeichen“. Die Vorgabe false entfernt sie. Der Name beschreibt, was der Decoder ignoriert, und nicht, was bei Ihnen ankommt. Wer ihn auf die naheliegende Weise liest, bekommt einen Decoder, der genau das Byte bewahrt, das Sie löschen wollten.

Warum es im Browser funktioniert und in Node bricht

Das ist die häufigste Spielart des Problems: Dieselbe JSON-URL lässt sich im Frontend-Code problemlos parsen und wirft in dem Moment, in dem ein Node-Skript die Datei von der Festplatte liest. An der Datei hat sich nichts geändert. res.json() dekodiert über dieselbe Maschinerie wie TextDecoder und verwirft die BOM unterwegs; fs.readFileSync(path, 'utf8') ist eine originalgetreue Dekodierung, die Ihnen jedes Zeichen aushändigt, das die Datei enthält, U+FEFF eingeschlossen.

Dieselbe Asymmetrie erklärt, warum require('./config.json') funktioniert und JSON.parse(fs.readFileSync('./config.json', 'utf8')) nicht. Der JSON-Modullader von Node entfernt die BOM, der manuelle Weg nicht.

Die BOM entfernen

const fs = require('fs');
const raw = fs.readFileSync('data.json', 'utf8');
const data = JSON.parse(raw.replace(/^/, ''));

Verankern Sie das Muster mit ^. Ein nicht verankertes globales Ersetzen würde auch legitime U+FEFF-Zeichen innerhalb von Zeichenkettenwerten löschen, und das wäre Datenverlust.

Eine unauffälligere Alternative, die eher zufällig funktioniert: JSON.parse(raw.trim()) gelingt ebenfalls, weil ECMAScript U+FEFF als Leerraum einstuft und String.prototype.trim es entfernt. Das Verhalten ist echt und oben nachgeprüft, aber es hängt an der JavaScript-Spezifikation und lässt sich nicht auf andere Sprachen übertragen. Pythons str.strip() lässt ein U+FEFF stehen, wo es steht.

Wenn Sie sicherstellen wollen, dass das bereinigte Ergebnis wirklich gültig ist und nicht bloß keinen Fehler mehr wirft, fügen Sie es in den JSON-Formatierer und -Validator ein. Ist die BOM einmal weg, bleiben als Kandidaten an Position 0 die gewöhnlichen Escaping-Probleme, die der Guide zum Escapen von JSON-Strings behandelt.

5. Die Lösung in Python: utf-8-sig

Python ist die einzige Laufzeitumgebung, die das Problem in der Fehlermeldung beim Namen nennt. Öffnen Sie eine Datei mit vorangestellter BOM als reines UTF-8, und json liefert Ursache und Lösung im selben Satz:

JSONDecodeError: Unexpected UTF-8 BOM (decode using utf-8-sig): line 1 column 1 (char 0)

Wenn Sie nach unexpected utf-8 bom gesucht haben und hier gelandet sind, stammt dieser Suchbegriff aus genau dieser Meldung. Der Codec, auf den sie verweist, liest die BOM als Signatur und verwirft sie:

import json

with open('data.json', encoding='utf-8-sig') as f:
    data = json.load(f)

utf-8-sig ist auch bei Dateien ohne BOM unbedenklich. Es entfernt eine vorhandene BOM und verhält sich ansonsten wie reines UTF-8. Für jede Datei, die Sie nicht selbst erzeugt haben, ist es damit die richtige Vorgabe.

Bytes und Text verhalten sich unterschiedlich

Eine Asymmetrie, die den Fehler sporadisch wirken lässt:

import json

json.loads(open('data.json', 'rb').read())       # {'a': 1}      funktioniert
json.loads(open('data.json', encoding='utf-8').read())  # wirft den Fehler von oben

json.loads führt bei bytes zuerst eine Encoding-Erkennung durch, entdeckt die BOM und dekodiert für Sie mit utf-8-sig. Geben Sie ihm ein bereits dekodiertes str, gibt es nichts mehr zu erkennen, und das U+FEFF erreicht den Parser. Zwei Codepfade, die gleichwertig aussehen, von denen einer den Fall stillschweigend abfängt.

Eine BOM absichtlich schreiben

Derselbe Codec läuft auch rückwärts, und so erzeugen Sie eine Datei für Excel:

with open('report.csv', 'w', encoding='utf-8-sig', newline='') as f:
    f.write('name\n')

Diese Datei beginnt mit ef bb bf. Abschnitt 7 behandelt, wann Sie genau das wollen.

Die CSV-Falle

csv.DictReader tut bei Text mit vorangestellter BOM genau das, was ein korrekter CSV-Parser tun soll, und erzeugt einen Schlüssel, den niemand treffen kann:

import csv, io

data = 'name,age\nAlice,30\n'
print(list(next(csv.DictReader(io.StringIO(data))).keys()))
# ['name', 'age']

Ihre erste Spalte heißt nicht name. Sie heißt U+FEFF gefolgt von name, und jeder Zugriff über row['name'] wirft KeyError, während die Kopfzeile in jedem Debugger korrekt aussieht. Öffnen Sie die Datei mit encoding='utf-8-sig', dann ist die BOM weg, bevor der Reader sie überhaupt zu Gesicht bekommt.

6. Die BOM in Java, Go, PHP und der Shell entfernen

Jede Lösung ist dieselbe Lösung auf einer anderen Ebene: drei Bytes löschen (EF BB BF) oder ein Zeichen löschen (U+FEFF), je nachdem, ob Sie Bytes oder Text in der Hand halten. Hat Ihre Sprache keinen BOM-bewussten Codec, machen Sie es von Hand.

Java dekodiert die BOM in ein führendes Zeichen :

String text = Files.readString(path, StandardCharsets.UTF_8);
if (!text.isEmpty() && text.charAt(0) == '') {
    text = text.substring(1);
}

Go, auf Byte-Ebene vor dem Unmarshalling:

raw, err := os.ReadFile("data.json")
if err != nil {
    return err
}
raw = bytes.TrimPrefix(raw, []byte{0xEF, 0xBB, 0xBF})

var v map[string]any
err = json.Unmarshal(raw, &v)

PHP, mit einem byte-verankerten Muster:

$raw  = file_get_contents('data.json');
$raw  = preg_replace('/^\xEF\xBB\xBF/', '', $raw);
$data = json_decode($raw, true);

Um die BOM aus einer Datei statt aus einer Variablen zu entfernen, vier Befehle. Alle vier liefen gegen eine Datei, die mit ef bb bf beginnt:

# In place, GNU sed (Linux). Die Escapes expandiert die Shell, nicht sed.
sed -i $'1s/^\xEF\xBB\xBF//' data.json

# In place, BSD sed (macOS)
sed -i '' $'1s/^\xEF\xBB\xBF//' data.json

# In place, überall dort, wo es Perl gibt. Nur die erste Zeile.
perl -i -pe 's/^\x{ef}\x{bb}\x{bf}// if $. == 1' data.json

# Kopie ohne die ersten drei Bytes. Nur sicher, wenn Sie wissen, dass dort eine BOM steht.
tail -c +4 data.json > clean.json

Die tail-Variante ist die grobe: Sie entfernt drei Bytes, ganz gleich, ob diese Bytes eine BOM waren. Bestätigen Sie es zuerst mit Abschnitt 2.

7. Die CSV-Ausnahme: wenn Excel die BOM braucht

Alles bisher Gesagte behandelt die BOM als Schaden. An einer Stelle ist sie tragend, und sie zu löschen macht eine funktionierende Datei kaputt.

Suchanfragen zu csv bom excel teilen sich in zwei entgegengesetzte Beschwerden, ein gutes Anzeichen dafür, dass hier jemand eine einzige Regel in die falsche Richtung anwendet:

  1. „Meine CSV öffnet sich in Excel mit é und æ¥æ¬èª statt echter Zeichen.“ Die BOM fehlt.
  2. „Meine erste Spalte heißt name und mein Skript findet sie nicht.“ Die BOM ist da.

Warum Excel sie haben will

Excel unter Windows hat keine verlässliche Möglichkeit zu erkennen, dass eine CSV in UTF-8 vorliegt. Es gibt keinen Header und keine Deklaration: Eine .csv-Datei besteht aus Bytes. Ohne Signal fällt Excel auf das Systemgebietsschema zurück, also Windows-1252 in den USA und Westeuropa, Windows-1251 in Russland, und jedes Nicht-ASCII-Zeichen kommt falsch heraus. Die BOM ist genau dieses Signal. Drei Bytes am Anfang, und Excel liest UTF-8 korrekt.

Damit ist die BOM in CSV eher ein Feature als ein Defekt, und daraus folgt eine Regel in einer Zeile:

Für eine Maschine zum Parsen geschrieben: BOM entfernen. Für einen Menschen zum Doppelklicken in Excel geschrieben: BOM behalten.

Der Fehlschlag auf der anderen Seite

Geben Sie dieselbe Datei einem Parser, verschmilzt die BOM mit Ihrer ersten Kopfzeilenzelle. In Node:

const header = 'name,age'.split(',');
console.log(JSON.stringify(header));   // ["name","age"]

const row = { 'name': 'Alice', age: 30 };
console.log(row.name);                 // undefined

row.name ist undefined, während der Schlüssel in Ihren Logs und in Ihrer console.table als name erscheint. Das ist derselbe Fehlertyp wie der KeyError in Python aus Abschnitt 5, und deshalb lohnt es sich, „der Feldname stimmt, aber der Wert fehlt“ sofort als BOM-Symptom zu behandeln.

Unsere eigenen Konverter nehmen bewusst beide Seiten ein. Der CSV-zu-JSON-Konverter entfernt eine führende BOM aus der Eingabe, bevor er parst, sodass eine Datei direkt aus Excel name ergibt und nicht name. In die andere Richtung macht der JSON-zu-CSV-Konverter die BOM zu einem ausdrücklichen Schalter, und seine Excel-Voreinstellung aktiviert sie zusammen mit Semikolon als Trennzeichen und CRLF-Zeilenenden, also genau der Kombination, die europäische Excel-Gebietsschemata tatsächlich brauchen. Alles Weitere zu Trennzeichen, Quoting und Typerkennung steht im Guide zur CSV-JSON-Konvertierung.

8. Über JSON hinaus: wo eine BOM sonst noch auftaucht

JSON macht viel Lärm darum. Andere Formate nicht.

Shell-Skripte. Eine BOM sitzt zwischen dem Dateianfang und dem #!, sodass der Kernel nie einen Shebang sieht und Ihren Interpreter nie startet. Unter macOS fiel die Shell im Test auf sh zurück und meldete die Shebang-Zeile als fehlende Datei:

./bom.sh: line 1: #!/bin/sh: No such file or directory

Das Skript lief anschließend trotzdem, nur unter dem falschen Interpreter, und das ist schlimmer als ein Abbruch. Andere Systeme formulieren es anders, am bekanntesten als bad interpreter-Fehler. Wenn ein Skript mit einem völlig korrekten #!/usr/bin/env python3 darauf beharrt, dieser Pfad existiere nicht, prüfen Sie die Bytes.

PHP. Alles außerhalb von <?php ... ?> ist Ausgabe, und eine BOM vor dem öffnenden Tag sind drei Bytes Ausgabe, die den Client erreichen, bevor Ihr Code läuft. Der erste Aufruf von header(), session_start() oder setcookie() scheitert dann mit der klassischen Warnung headers already sent, die auf Zeile 1 einer Datei zeigt, deren Zeile 1 leer aussieht.

.env-Dateien und jedes Schlüssel-Wert-Format. Derselbe Mechanismus wie im CSV-Fall: Ihre erste Variable heißt nicht DATABASE_URL, sondern U+FEFF gefolgt von DATABASE_URL, also geht der Zugriff ins Leere, während die Datei für einen Menschen korrekt aussieht. Jede weitere Variable funktioniert, und deshalb wirkt es wie ein Problem mit einer einzigen Einstellung.

XML ist die Ausnahme in die andere Richtung. Die XML-Spezifikation erlaubt eine UTF-8-BOM am Dokumentanfang ausdrücklich als Teil der Encoding-Autoerkennung, und Parser müssen damit umgehen können. Pythons xml.etree.ElementTree hat ein Dokument mit vorangestellter BOM im Test klaglos akzeptiert. Wenn XML fehlschlägt, liegt es vermutlich nicht an der BOM.

9. An der Quelle abstellen

Sobald Sie den Mechanismus verstanden haben, geht es nicht mehr darum, die BOM aus einer Datei zu entfernen. Es geht darum, dass die Datei nicht wieder eine bekommt.

Legen Sie die Kodierung in .editorconfig fest. Die Eigenschaft charset kennt utf-8 und utf-8-bom als getrennte Werte, Sie schreiben also genau hin, was Sie wollen:

[*]
charset = utf-8

Prüfen Sie die Editor-Einstellung, die das überschreibt. In VS Code ist das "files.encoding": "utf8", und der Wert, nach dem Sie suchen, ist utf8bom. Sehen Sie sowohl in der Workspace-Datei .vscode/settings.json als auch in Ihren Benutzereinstellungen nach, denn eine eingecheckte Workspace-Einstellung gilt stillschweigend für alle im Team.

Scannen Sie in der CI oder in einem Pre-Commit-Hook. Das hier ist portabel und hat keine Abhängigkeiten. Es beendet sich mit einem Wert ungleich null, sobald es etwas findet:

#!/bin/sh
# Fehlschlagen, wenn eine versionierte Datei mit EF BB BF beginnt
found=0
for f in $(git ls-files '*.json' '*.md' '*.sh'); do
  if [ "$(head -c3 "$f" | od -An -tx1 | tr -d '[:space:]')" = "efbbbf" ]; then
    echo "BOM: $f"
    found=1
  fi
done
exit $found

In beide Richtungen geprüft: Es listet die betroffenen Pfade auf und beendet sich mit 1, wenn eine Datei mit BOM versioniert ist, und mit 0, sobald die Dateien sauber sind.

Schreiben Sie die eine erlaubte Ausnahme auf. Eine Regel „nirgendwo eine BOM“ bricht beim ersten Tabellenexport, den jemand braucht, und danach hält sich niemand mehr daran. Benennen Sie stattdessen die Ausnahme: BOMs sind in CSV-Dateien erlaubt, die für Excel bestimmt sind, sonst nirgends. Nehmen Sie das Exportverzeichnis vom Scanner aus, dann überlebt die Regel den Kontakt mit der Wirklichkeit.

10. Eine Bisektion in sechzig Sekunden

Arbeiten Sie der Reihe nach ab. Jeder Schritt beendet entweder die Untersuchung oder übergibt dem nächsten ein kleineres Problem.

  1. Lesen Sie das Zeichen, nicht die Position. Abschnitt 1. Ein < heißt HTML, dann sind Sie hier fertig. Kein zitiertes Zeichen heißt leerer Body. Ein unlesbares Kästchen heißt weitermachen.
  2. Bestätigen Sie die Bytes. hexdump -C file | head -1. Sind die ersten drei Bytes nicht ef bb bf, hören Sie auf: Das ist keine BOM, und nichts weiter unten hilft.
  3. Finden Sie die Eintrittsstelle. Trägt die Datei die BOM schon auf der Festplatte, oder taucht sie erst auf, wenn Ihr Code sie in Händen hält? Ist die Datei auf der Festplatte sauber, fügt etwas in Ihrer Pipeline sie hinzu.
  4. Wählen Sie eine Seite für die Korrektur. Entfernen Sie beim Lesen, wenn der Erzeuger ein Anbieter, ein Upload oder ein Build-Schritt ist, der Ihnen nicht gehört. Korrigieren Sie den Erzeuger, wenn er Ihnen gehört, denn die Lösung auf der Leseseite müssen Sie bei jedem einzelnen Leser wiederholen.
  5. Setzen Sie die Korrektur an der Dekodiergrenze an, nicht tiefer. encoding='utf-8-sig' beim Aufruf von open(), kein .lstrip() auf einer Zeichenkette drei Funktionen später. Tief im Stack korrigiert heißt, dass der nächste Codepfad, der die Datei liest, den Fehler neu entdecken darf.
  6. Prüfen Sie nach, dass sich die Bytes geändert haben. Wiederholen Sie Schritt 2. Eine Korrektur, die in einem Codepfad funktioniert und dabei die Datei unangetastet lässt, scheitert im nächsten.
  7. Richten Sie den Scanner ein. Abschnitt 9. Sonst machen Sie das alles im nächsten Quartal noch einmal.

FAQ

Ist die UTF-8-BOM vorgeschrieben?

Nein. UTF-8 hat nur eine einzige Bytereihenfolge, es gibt also nichts, was eine Markierung unterscheiden müsste. Unicode erlaubt eine UTF-8-BOM als Kodierungssignatur, empfiehlt sie aber nicht, und JSON verbietet sie rundheraus: RFC 8259 legt fest, dass Implementierungen einem JSON-Text keine Byte Order Mark voranstellen dürfen.

Warum sieht die Datei in meinem Editor gut aus, lässt sich aber nicht parsen?

Weil U+FEFF überhaupt nichts darstellt. Editoren, die es erkennen, blenden das Zeichen aus und erwähnen stattdessen UTF-8 with BOM in der Statusleiste. Editoren, die es nicht erkennen, zeichnen schlicht null Pixel. cat, less und ein Diff im Code-Review sehen ebenfalls identisch aus. Nur eine Ansicht auf Byte-Ebene macht es sichtbar.

Entfernt JSON.parse die BOM jemals automatisch?

Nie. JSON.parse bekommt eine Zeichenkette und behandelt U+FEFF als unerwartetes Zeichen, wo immer es auftritt. Das erledigt die Schicht darüber: res.json() nach einem fetch, Nodes require() für .json-Dateien und TextDecoder in seiner Vorgabeeinstellung nehmen es alle heraus, bevor der Parser überhaupt etwas zu sehen bekommt.

Soll ich die BOM aus CSV-Dateien entfernen?

Das hängt davon ab, wer die Datei öffnet. Jeder Parser schlägt die BOM Ihrem ersten Spaltennamen zu, aus name wird also name, und jeder Zugriff geht daneben. Dort entfernen Sie sie. Excel unter Windows nutzt die BOM zur UTF-8-Erkennung und verstümmelt ohne sie Zeichen mit Akzenten sowie CJK-Zeichen, dort behalten Sie sie also.

Ist die BOM dasselbe wie ein Zero-Width Space?

Derselbe Codepunkt, andere Aufgabe. U+FEFF an Offset 0 ist eine Byte Order Mark. An jeder anderen Stelle in einem Dokument ist es ZERO WIDTH NO-BREAK SPACE, eine Verwendung, die Unicode zugunsten von U+2060 WORD JOINER für veraltet erklärt hat. Alter Text enthält es weiterhin, und deshalb taucht U+FEFF auch mitten in Dateien auf.

Wirkt sich die BOM auf Git-Diffs und die Dateigröße aus?

Drei Bytes auf der Festplatte und eine störende Zeile in jedem Diff, der sie berührt. Git vergleicht Bytes, das Hinzufügen oder Entfernen einer BOM schreibt also Zeile 1 neu, selbst wenn der dargestellte Text identisch ist. Daher stammt die Ein-Zeilen-Änderung, die im Review niemand erklären kann.

Tags: utf-8 bom json csv debugging character-encoding

Verwandte Artikel

Alle Artikel anzeigen