Seit Emacs 23 ist UTF-8 der Default — der Alltag funktioniert „einfach". Aber sobald deutsche Sonderzeichen plötzlich kaputt aussehen, Windows-Dateien mit ^M enden oder ein BOM auftaucht, lohnt der Blick auf das Coding-System. Das ist der Mechanismus, mit dem Emacs Bytes auf Zeichen und Zeilenumbrüche abbildet — eine kleine, aber sehr alte Schicht direkt zwischen Datenträger und Buffer. Dieser Artikel erklärt das Konzept, zeigt, wie man Encoding und Zeilenende-Konvention manuell wechselt, übersetzt die Modeline-Kürzel und sammelt die Werkzeuge, mit denen Windows-Dateien sauber nach Unix konvertiert werden.

Was ein Coding-System ist

Ein Coding-System in Emacs ist kein reines „Encoding" im Sinne von „UTF-8 oder Latin-1", sondern ein Bündel aus drei Eigenschaften:

BestandteilBeispieleBedeutung
Character Encodingutf-8, latin-1, windows-1252, iso-8859-15, shift_jiswelche Bytes auf welche Unicode-Zeichen abgebildet werden
End-of-Line-Konventionunix (\n), dos (\r\n), mac (\r)wie Zeilenwechsel kodiert sind
Optionale Flags-with-signature (BOM), automatische Dekompression bei .gzSonderfälle wie Byte-Order-Mark oder transparente gzip-Entpackung

In der Schreibweise hängt Emacs Encoding und EOL mit Bindestrichen aneinander: utf-8-unix, utf-8-dos, latin-1-unix, windows-1252-dos, iso-8859-15-unix. Das Schema ist immer dasselbe — <encoding>-<eol>. Jedes Encoding kann mit jeder EOL-Konvention kombiniert werden; latin-1-dos ist genauso legitim wie utf-8-unix.

Einige Coding-Systeme bringen weitere Flags mit:

text Beispiele für vollständige Coding-System-Namen
utf-8-unix                   UTF-8, Unix-EOL
utf-8-dos                    UTF-8, CRLF-EOL (typisch Windows)
utf-8-with-signature-unix    UTF-8 mit BOM, Unix-EOL
utf-8-auto                   UTF-8 mit automatischer EOL-Erkennung
utf-16le-with-signature      UTF-16 Little-Endian mit BOM (klassisch Windows)
latin-1-unix                 ISO-8859-1, Unix-EOL
iso-8859-15-unix             ISO-8859-15 (Latin-9, mit €-Zeichen)
windows-1252-dos             Windows-Codepage 1252, CRLF
no-conversion                roh — keinerlei Konvertierung
prefer-utf-8                 UTF-8 bevorzugt, mit Fallback bei nicht-UTF-8-Bytes

Die vollständige Liste zeigt M-x list-coding-systems — pro Eintrag mit Mnemonic-Buchstabe, Alias und Kurzbeschreibung. Für ein einzelnes Coding-System liefert M-x describe-coding-system Detailinformationen.

Wie Emacs das Coding-System einer Datei erkennt

Beim Öffnen einer Datei prüft Emacs in einer festen Reihenfolge, welches Coding-System gelten soll. Der Mechanismus ist mehrstufig — das ist der Grund, warum „einfach UTF-8" zu 99 % funktioniert, ohne dass du etwas konfigurieren musst.

StufeQuelleWirkung
1auto-coding-alistharte Regel über Dateinamen-Muster — z. B. .tarno-conversion
2auto-coding-regexp-alistInhalts-Pattern in den ersten Bytes — z. B. BOM EF BB BFutf-8-with-signature
3File-Local-Variable-*- coding: utf-8 -*- in der ersten oder letzten Zeile der Datei
4auto-coding-functionsFunktionen, die in den Inhalt schauen — etwa der XML-Header <?xml encoding="..."?>
5file-coding-system-alistRegex über Dateinamen — z. B. \\.txt\\'prefer-utf-8
6Default-Heuristikprefer-utf-8 (seit Emacs 23) — testet UTF-8, fällt bei kaputten Bytes auf Latin-1 zurück

Wichtig: Eine explizite coding:-Angabe in der Datei selbst überschreibt file-coding-system-alist — Datei-lokale Festlegung gewinnt. Die Default-Heuristik greift nur, wenn keine der oberen Stufen ein Coding-System bestimmt hat.

Wenn dich interessiert, wie Emacs eine bestimmte Datei entschieden hat: öffne sie, dann C-h v buffer-file-coding-system RET oder schau in die Modeline (siehe nächste Sektion). Welche Datei sich Emacs „nicht traut", siehst du an der Frage „Select coding system" beim Öffnen — sie erscheint, wenn die Auto-Detection keine eindeutige Antwort findet.

Encoding und EOL in der Modeline lesen

Der linke Block der Modeline zeigt Encoding und Zeilenende-Konvention auf engstem Raum. Die wichtigsten Mnemonics in Kurzform:

ZeichenBedeutung
UUTF-8-Familie
1ISO-Latin-1 (ISO-8859-1)
=no-conversion — bytegenau, keine Umwandlung
-Default / undecided
JJapanisch (ISO-2022-JP)
SShift-JIS
CChinesisch (Big5)

Direkt hinter den drei Encoding-Zeichen steht ein Trenn-Zeichen, das die EOL-Konvention kodiert:

TrennerEOL-KonventionBytesTypisches System
:UnixLFmacOS, Linux, BSD
\DOSCRLFWindows-Editoren
/Mac (classic)CRMac OS 9 und älter

In der Praxis ergeben sich daraus drei Modeline-Stücke, die du immer wieder sehen wirst:

text Linker Modeline-Block in der Praxis
-UUU:----      UTF-8 auf Tastatur/Terminal/Datei, Unix-EOL    (Default macOS/Linux)
-UUU\----      UTF-8, aber CRLF-EOL                          (Windows-Datei)
-11=:----      Latin-1 in/out, no-conversion fürs Schreiben   (selten, aber möglich)
-===:----      no-conversion komplett — Binärdatei            (z. B. ausgehexter Buffer)

Die Reihenfolge der drei Encoding-Zeichen ist Eingabe — Ausgabe — Datei. In gut konfigurierten Setups stehen dort drei mal dasselbe Zeichen. Die vollständige Aufschlüsselung jedes Modeline-Felds — inklusive Modified-Indikator, Read-Only-Flag und Frame-Nummer — findest du im Artikel Modeline lesen.

Encoding manuell setzen oder ändern

Drei Befehle decken praktisch alle Coding-System-Wechsel ab. Für jeden gibt es ein klassisches Tastenkürzel (über die Prefix-Sequenz C-x RET) und einen sprechenden M-x-Namen.

BefehlTastenkombiWirkung
set-buffer-file-coding-systemC-x RET fCoding-System fürs nächste Speichern des Buffers setzen
revert-buffer-with-coding-systemC-x RET rDatei neu laden und dabei mit anderem Coding-System interpretieren
universal-coding-system-argumentC-x RET cCoding-System nur für den unmittelbar folgenden Befehl erzwingen
prefer-coding-systemM-x prefer-coding-systemglobale Default-Präferenz für künftige Operationen verschieben
recode-regionM-x recode-regionfalsch dekodierten Bereich neu einlesen — Notbremse, wenn Stufe 1 schon misslang
find-file-literallyM-x find-file-literallyDatei komplett ohne Konvertierung öffnen (Bytes wie sie sind)

Die Faustregel zum Unterscheiden:

  • Inhalt sieht kaputt ausrevert-buffer-with-coding-system (Datei lesen mit anderem Encoding)
  • Inhalt sieht richtig aus, soll aber anders gespeichert werdenset-buffer-file-coding-system (Datei schreiben mit anderem Encoding)

Der typische „Windows-Datei sauber nach Unix konvertieren"-Workflow sieht so aus:

  1. Datei mit C-x C-f öffnen.
  2. Modeline prüfen — steht da \ als Trenner? Dann ist es DOS-EOL.
  3. C-x RET f oder M-x set-buffer-file-coding-system RET utf-8-unix RET.
  4. Speichern mit C-x C-s .

Beim nächsten Öffnen zeigt die Modeline : statt \ — die Datei ist konvertiert.

CRLF und Windows-Dateien

Das häufigste EOL-Problem im deutschen Entwickleralltag: Eine Datei kommt von einem Windows-Kollegen, aus einem Windows-Repo oder aus einem Windows-Build-Tool — und plötzlich zeigt Emacs am Zeilenende ein sichtbares ^M, oder die Modeline meldet dos statt unix. Was steckt dahinter?

Emacs unterscheidet zwei Fälle:

  • Datei wird als dos erkannt: alles in Ordnung, das \r\n wird transparent abgebildet — du siehst keine ^M und kannst normal arbeiten. Die Datei behält beim Speichern CRLF.
  • Datei wird als unix erkannt, enthält aber trotzdem CR-Bytes: dann interpretiert Emacs jedes \r als gewöhnliches Steuerzeichen und zeigt es als ^M an. Das passiert oft bei gemischten Zeilenenden oder wenn ein anderer Modus die Auto-Detection überschrieben hat.

Vier Strategien, je nach Ziel:

ZielVorgehen
CRLF behalten (z. B. Windows-Tool-Datei)nichts tun — Emacs zeigt sauber an und speichert wieder als CRLF
CRLF nach LF konvertierenC-x RET futf-8-unixC-x C-s
Per Datei fixieren (Datei-lokal)erste Zeile mit -*- coding: utf-8-unix -*- ergänzen
Per Projekt erzwingen (plattformübergreifend).gitattributes mit * text=auto eol=lf oder .editorconfig mit end_of_line = lf

Wenn die ^M schon im Buffer stehen und auch nach set-buffer-file-coding-system bleiben, liegt es daran, dass die Datei wirklich CR-Bytes enthält, nicht nur CRLF-Paare. In dem Fall hilft M-x replace-string RET C-q C-m RET RETC-q C-m fügt im Minibuffer ein wörtliches Carriage-Return ein, das durch nichts ersetzt wird.

Für Projekte, in denen Windows- und Unix-Nutzer parallel arbeiten, ist die nachhaltigste Lösung eine .gitattributes-Datei im Repo-Root:

text .gitattributes — Zeilenenden projektweit normalisieren
# Alle Textdateien beim Check-out auf LF zwingen
* text=auto eol=lf

# Windows-spezifische Skripte explizit als CRLF behalten
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf

Damit ist Emacs aus dem EOL-Spiel raus — Git liefert konsistente Bytes, und das Coding-System pro Buffer wird wieder zur Randnotiz.

Byte-Order-Mark (BOM) und UTF-16

Einige Windows-Tools — Notepad in älteren Versionen, manche Office-Exports, ältere .csv-Exporte aus Excel — speichern UTF-8 mit BOM (EF BB BF als erste drei Bytes). Emacs erkennt das und nutzt dann das Coding-System utf-8-with-signature statt utf-8. Beide sind funktional kompatibel, aber sie sind verschiedene Coding-Systeme:

Coding-SystemBedeutung
utf-8UTF-8, ohne BOM beim Speichern
utf-8-with-signatureUTF-8, mit BOM beim Speichern
utf-8-autoUTF-8, BOM wird beim Lesen erkannt — geschrieben wird ohne BOM
utf-16le-with-signatureUTF-16 Little-Endian mit BOM (Windows-Standard für UTF-16)
utf-16be-with-signatureUTF-16 Big-Endian mit BOM
utf-16le / utf-16beUTF-16 ohne BOM (Endianness wird erzwungen)

UTF-16 hat in der Regel immer ein BOM, weil sonst nicht entscheidbar ist, ob 00 41 für A oder für steht. Bei UTF-8 ist das BOM technisch überflüssig — und in der Praxis schädlich:

  • #!/bin/bash-Shebangs werden ungültig, weil das BOM vor das # rutscht.
  • PHP gibt das BOM als „leere Ausgabe" mit aus und blockiert header()-Aufrufe.
  • Manche XML-Parser, JSON-Parser und Build-Tools werfen Syntax-Fehler.

Wenn du eine UTF-8-Datei mit unerwartetem BOM erbst und es loswerden willst:

text BOM aus einer Datei entfernen
1. Datei öffnen — Modeline zeigt typischerweise ein "U" mit BOM-Hinweis
2. M-x set-buffer-file-coding-system RET utf-8-unix RET   (ohne -with-signature)
3. C-x C-s

Umgekehrt: wer ein BOM bewusst setzen will (z. B. weil ein Windows-Tool das erwartet), nutzt utf-8-with-signature-unix oder utf-8-with-signature-dos. Das ist eine bewusste, dokumentierte Entscheidung — und keine, die durch Zufall passieren sollte.

latin-1 und andere alte Encodings

Auch wenn UTF-8 heute der Default ist, begegnest du im Alltag immer wieder älteren Encodings. Die typischen Verdächtigen:

EncodingWann es auftaucht
iso-8859-1 (Latin-1)deutsche Textdateien aus den 90ern und frühen 2000ern
iso-8859-15wie Latin-1, aber mit Euro-Zeichen — typisch für EU-Behörden-Dokumente
windows-1252Windows-Default vor UTF-8-Zeitalter, fast identisch mit Latin-1
cp850 / cp437DOS-Codepages — Logs, alte Batch-Skripte
shift_jis, gb2312, big5japanische, chinesische und taiwanesische Texte aus älteren Tools
ebcdicMainframe-Output (IBM)

Das Vorgehen ist immer dasselbe — und ein gutes Beispiel für den Unterschied zwischen revert-buffer-with-coding-system und set-buffer-file-coding-system:

text Falsch erkannte Datei zu UTF-8 konvertieren
1. Datei öffnen — Umlaute sehen aus wie "ä" oder "?" oder "\223"
2. M-x revert-buffer-with-coding-system RET windows-1252 RET
   → Datei wird NEU GELADEN, jetzt sehen Umlaute korrekt aus
3. M-x set-buffer-file-coding-system RET utf-8-unix RET
   → ab jetzt wird als UTF-8 gespeichert
4. C-x C-s
   → Datei ist dauerhaft konvertiert

Wer sich nicht sicher ist, welches Encoding richtig ist, probiert nacheinander windows-1252, iso-8859-15, iso-8859-1 durch — bei deutschen Texten ist windows-1252 der häufigste Treffer, weil Windows-Tools historisch dieses Encoding statt strict-Latin-1 nutzten.

Globale Defaults sauber setzen

Für die meisten Setups ist die Empfehlung eindeutig: alles auf UTF-8 mit Unix-EOL als Default, Sonderfälle pro Datei oder pro Projekt regeln. Das Snippet dafür ist kurz:

elisp init.el — UTF-8 als globaler Default
;; Alles UTF-8 — Eingabe, Ausgabe, Datei, Prozesse
(set-default-coding-systems 'utf-8-unix)
(prefer-coding-system 'utf-8-unix)
(setq-default buffer-file-coding-system 'utf-8-unix)

;; Auch das Locale-Environment zwingt Emacs auf UTF-8 (Subprozesse, Clipboard)
(set-language-environment "UTF-8")

;; Clipboard auf macOS/Linux/Windows konsistent als UTF-8 interpretieren
(set-selection-coding-system 'utf-8)

Wichtig zu verstehen: diese Zeilen ändern nicht das Auto-Detection-Verhalten. Dateien mit anderem Encoding werden weiterhin korrekt erkannt und behalten ihr Encoding beim Speichern — die Defaults greifen nur für neue Buffer und für Fälle, in denen Auto-Detection nichts Eindeutiges findet.

Was wohin gehört, erklärt der Artikel init.el und early-init.el ausführlich — in Kurzform: das Snippet kommt in ~/.config/emacs/init.el (oder ~/.emacs.d/init.el) und gilt nach dem nächsten Emacs-Start.

Wer auf Windows arbeitet und dort grundsätzlich CRLF will, ersetzt utf-8-unix durch utf-8-dos. Der robustere Weg ist allerdings, das Encoding auf UTF-8 zu fixieren und EOL pro Projekt über .gitattributes oder .editorconfig zu steuern — das funktioniert auch dann, wenn Kollegen mit anderen Editoren arbeiten.

Häufige Stolperfallen

Ein Coding-System steckt drei Dinge in einen Namen

utf-8-unix ist nicht „UTF-8" mit Bonus-Bindestrich, sondern Encoding (UTF-8) + EOL (Unix-LF) + ggf. Flags (z. B. -with-signature für BOM) in einer einzigen Zeichenkette. Wer das mitliest, versteht sofort, warum utf-8-unix und utf-8-dos unterschiedliche Coding-Systeme sind — obwohl beide UTF-8 sind.

Modeline-Trenner `:` vs. `\\` vs. `/` ist die EOL-Anzeige

Direkt nach den drei Encoding-Buchstaben steht ein einzelnes Zeichen — : für Unix, \ für DOS (CRLF), / für klassisches Mac (CR). Das ist leicht zu übersehen, weil es wie ein zufälliger Trenner aussieht. Wer den Trenner liest, sieht CRLF-Probleme, bevor sie weh tun.

`^M` heißt: Datei als unix geladen, enthält aber CR

Wenn Emacs am Zeilenende ^M (Caret-M) anzeigt, ist das Coding-System des Buffers unix, aber die Datei enthält trotzdem CR-Bytes. set-buffer-file-coding-system RET utf-8-unix + Speichern entfernt sie. Bei rein gemischten Zeilenenden hilft zusätzlich M-x replace-string RET C-q C-m RET RET.

BOM in UTF-8 bricht oft Shell-Skripte und Web-Tools

EF BB BF als Datei-Anfang macht #!/bin/bash ungültig, blockiert PHP-header()-Aufrufe und stolpert in manchen XML-Parsern. Beim Konvertieren bewusst utf-8 (ohne -with-signature) wählen — nicht aus Versehen die -with-signature-Variante stehen lassen.

`prefer-utf-8` ist klüger als pures `utf-8`

Der Default seit Emacs 23 ist prefer-utf-8 — das versucht UTF-8 zuerst und fällt bei nicht-dekodierbaren Bytes automatisch auf Latin-1 zurück. Wer (prefer-coding-system 'utf-8) schreibt statt 'utf-8-unix oder 'prefer-utf-8, verliert diesen Schutz und bekommt bei kaputten Bytes harte Lese-Fehler.

`utf-8-with-signature` und `utf-8` sind verschiedene Coding-Systeme

Auch wenn beide UTF-8 sind: das eine schreibt ein BOM, das andere nicht. Wer eine Datei mit BOM öffnet und einfach C-x C-s macht, schreibt das BOM wieder mit. Wer das BOM loswerden will, muss explizit auf utf-8 (ohne -with-signature) umstellen.

`.editorconfig` und `.gitattributes` schlagen jede init.el

Eine Encoding- und EOL-Policy im Repo (.gitattributes mit * text=auto eol=lf, oder .editorconfig mit charset = utf-8 und end_of_line = lf) wirkt für alle Editoren und alle Teammitglieder — robuster als persönliche init.el-Snippets, die nur den eigenen Emacs konfigurieren.

`revert-buffer-with-coding-system` liest neu — `set-buffer-file-coding-system` schreibt

Wenn der Inhalt im Buffer kaputt aussieht, ist revert-buffer-with-coding-system fast immer die Lösung — es lädt die Datei mit anderem Encoding neu. set-buffer-file-coding-system ändert nur, wie beim nächsten Speichern geschrieben wird, und repariert keinen falsch dekodierten Buffer.

Weiterführende Ressourcen

Externe Quellen

Verwandte Artikel

/ Weiter

Zurück zu Dateien & Verzeichnisse

Zur Übersicht