Zeilenumbruch
Es gibt mehrere unterschiedliche Möglichkeiten, wie Zeilenumbrüche innerhalb von Textdateien realisiert sein können. In diesem Artikel möchten wir uns zunächst diese verschiedenen Arten von Zeilenumbruchtypen ansehen und anschließend sowohl auf die Probleme die durch diese Variabilität auftreten können eingehen als auch Lösungen und einige Anwendungsbeispiele für diese Probleme anbieten.
- Zeichenbasierte Zeilenumbruchtypen
- Zeilenumbrüche durch Definition einer festen Zeilenlänge
- Zeilenumbrüche im HTML-Quelltext und anderen Auszeichnungssprachen
- Zeilenumbrüche im Quellcode verschiedenener Programmiersprachen
- Erkennung des Zeilenumbruchtyps einer Datei
- Probleme beim Austausch von Dateien
- Änderung des Zeilenumbruchtyps von Dateien
- Dateien mit gemischten Zeilenumbrüchen
Grundsätzlich gibt es drei verschiedene Kategorien, in die wir die verschiedenen Arten von Zeilenumbruchtypen einordnen können: Zeichenbasierte Zeilenumbrüche, Zeilenumbrüche durch die Definition einer fixen Zeilenlänge sowie durch eine Auszeichnungssprache (markup) realisierte Zeilenumbrüche. In den folgenden Abschnitten möchten wir als Einführung in die Thematik als erstes diese drei Kategorien mitsamt ihrer prominentesten Vertreter gegenüberstellen.
Zeichenbasierte Zeilenumbruchtypen
Die meisten Plain-Textdateien verwenden zur Auszeichnung ihrer Zeilenumbrüche bestimmte zuvor definierte Zeichen beziehungsweise Bytes. Wenn das Programm, das eine solche Textdatei lesen, verarbeiten oder anzeigen soll, diese Zeichen kennt, weiß es, dass diese Zeichen nicht als Buchstabe angezeigt werden sollen sondern als (unsichtbare) Zeilenumbrüche interpretiert werden können.
Leicht umzusetzen wäre diese Vorgehensweise, wenn man sich im Laufe der Zeit auf ein einziges bestimmtes Zeichen für einen Zeilenumbruch geeinigt hätte. Dadurch dass die verschiedenen Systeme allerdings historisch gewachsen sind, ist dies bis heute nicht der Fall. Je nach Betriebssystem können daher andere Zeichen beziehungsweise Bytes für einen Zeilenumbruch verwendet werden.
Zeichen und Codepoints für Zeilenumbrüche und deren Verwendung
Die folgende Tabelle gibt eine Übersicht über die verschiedenen Zeichen sowie Zeichenkombinationen für Zeilenumbrüche und die gebräuchlichsten Systeme, die die jeweilige Art von Zeilenumbruch nutzen:
Abkürzung | Code (Hex/Dez) | Zeichensatz | System/Verwendung |
CR LF | 0D 0A / 13 10 | ASCII | Windows, MS-DOS, OS/2, Symbian OS, Palm OS, Atari TOS, CP/M, MP/M, RT-11, Amstrad CPC, DEC TOPS-10 sowie die meisten anderen frühen Nicht-Unix- und Nicht-IBM-Betriebssysteme |
LF | 0A / 10 | ASCII | Line Feed / Zeilenvorschub - Unix und Unix-ähnliche Systeme (Linux, macOS, Mac OS X, Android, BSD, AIX, Xenix und so weiter), Amiga, AmigaOS, QNX, Multics, BeOS, RISC OS und andere am POSIX-Standard orientierte Systeme |
CR | 0D / 13 | ASCII | Carriage Return / Wagenrücklauf - Mac OS (Classic) bis Version 9, Apple II, Lisa OS, Commodore 64 (C64), Commodore 128 (C128), Acorn BBC, ZX Spectrum, TRS-80, Oberon, HP Series 80, MIT Lisp Machine, OS-9 |
RS | 1E / 30 | ASCII | Record Separator / Datensatztrenner - QNX (vor der POSIX Implementierung mit Version 4) |
EOL | 9B / 155 | ATASCII | End Of Line - Atari 8-Bit Computer |
NL | 15 / 21 | EBCDIC | New Line - IBM Mainframe Systems wie z/OS (OS/390) oder IBM i (i5/OS, OS/400) |
LF | 25 / 37 | EBCDIC | Line Feed - EBCDIC-Zeichen für ASCIIs 0A |
RNL | 06 / 06 | EBCDIC | Require New Line (ab 2007) |
76 / 118 | ZX80/ZX81 | Sinclair Research Home Computers Linebreak | |
VT | U+000B | Unicode | Vertical Tab / Vertikaler Tab |
FF | U+000C | Unicode | Form Feed / Seitenvorschub |
NEL | U+0085 | Unicode | Next Line / Nächste Zeile |
LS | U+2028 | Unicode | Line Separator / Zeilentrenner |
PS | U+2029 | Unicode | Paragraph Separator / Absatztrenner |
Der weltweit am weitesten verbreitete und am häufigsten genutzte Zeichensatz ist ASCII (American Standard Code for Information Interchange) beziehungsweise der auf ASCII aufbauende Unicode-Standard. Diesem Zeichensatz entstammen auch die beiden gebräuchlichsten und am weitesten verbreiteten Zeilenumbruchtypen: Der Unix-Zeilenumbruch LF sowie der Windows-Zeilenumbruch CR LF.
Unix und das aktuelle macOS von Apple nutzen als Zeilenumbruch den Unicode-Codepoint U+000D während ältere Apple-Systeme U+000A verwenden. Windows und MS-DOS nutzen gleich beide dieser Zeichen hintereinander in der Reihenfolge 0D0A. Neben diesen drei Zeichen und Zeichenfolgen fordert der Unicode-Standard auch die am Ende der Tabelle dargestellten Code-Points U+000B (Vertical Tab VT, vertikaler Tabulator), U+000C (Form Feed FF, Seitenvorschub / Seitenumbruch = neue Seite), U+0085 (Next Line NEL, Nächste Zeile), U+2028 (Line Separator LS, Zeilentrenner) sowie U+2029 (Paragraph Separator PS, Absatztrenner) als Zeilenumbruch zu interpretieren. Dies tun bis heute jedoch nur wenige Programme.
Einer der bekanntesten Zeichensätze außerhalb der ASCII-Welt ist der von IBM für seine Großrechner entwickelte 8-Bit-Zeichensatz EBCDIC (Extended Binary Coded Decimal Interchange Code). In diesem Zeichensatz wird das hexadezimale Zeichen 15 (dezimal 21) für einen Zeilenumbruch verwendet, das die Funktionen von CR und LF kombiniert. Zusätzlich enthält EBCDIC aber auch noch die ASCII-typischen Zeichen CR und LF (wenn auch zweiteres unter einem anderen Zeichencode) sowie ab 2007 das weitere Zeichen RNL (Required New Line - "Neue Zeile benötigt"), das für die Kodierung eines bedingten automatischen Zeilenumbruchs verwendet werden kann.
Weniger verbreitet beziehungsweise nur von historischer Relevanz sind die Zeilenumbrüche EOL (End Of Line), der hauptsächlich in den 1980er genutzten Atari 8-Bit Computer aus dem von Atari genutzten 8-Bit-Zeichensatz ATASCII (ATARI Standard Code for Information Interchange), die ebenfalls in den 1980er Jahren von Sinclair Research Ltd für seine Computer verwendeten Zeilenumbrüche aus den Zeichensätzen ZX80 und ZX81 sowie der Zeilenumbruch RS (Record Separator), der bis zum Erscheinen der Version 4.0 im Jahre 1990 vom Betriebsystem QNX genutzt wurde. Einige historische Betriebsysteme definierten Zeilenumbrüche sogar auf Bit-Ebene: Betriebssysteme der CDC 6000 Serie aus den 1960er Jahren, zu einer Zeit als Speicher noch teuer war, definierten ihren Zeilenumbruch beispielsweise als zwei oder mehr mit Null-Bits gefüllte 6-Bit-Zeichen am Ende eines 60-Bit-Words.
Wieso besteht der Windows-Zeilenumbruch aus zwei Zeichen?
Dass Windows, MS-DOS sowie die meisten anderen frühen Nicht-Unix- und Nicht-IBM-Betriebssysteme ihren Zeilenumbruch im Gegensatz zu den genannten anderen Betriebssystemen durch gleich zwei Zeichen definieren, hat historische Gründe und ist zurückzuführen auf die Vorgehensweise von Schreibmaschinen und alten Druckgeräten:
Auf einer Schreibmaschine wird der Umbruch einer Zeile nämlich ebenfalls durch zwei voneinander unterscheidbaren Aktionen durchgeführt: Die Schreibstelle rückt einerseits zurück an den Anfang der Zeile (Wagenrücklauf) und die Schreibstelle geht andererseits eine Zeile nach unten, zum Beispiel indem das zu bedruckende Papier durch drehen der Walze weiter geschoben wird (Zeilenvorschub). Ein vollständiger "Zeilenumbruch" setzt sich gemäß dieser Logik demnach aus einer Kombination dieser beiden Aktionen zusammen. Als in den 1960er Jahren die Systeme für Zeichensätze für Computer entwickelt wurden, definierte man in diesen Zeichensätzen sowohl separate Steuerzeichen für den Wagenrücklauf als auch für den Zeilenvorschub, um die damalige Steuerung von Druckern in der gleichen Weise abbilden und realisieren zu können. Diese Historie schlägt sich bis zu den aktuellsten Windows-Versionen von heute nieder.
Der Wagenrücklauf (auf Englisch "Carriage Return" = CR) bekam im damaligen ASCII-Zeichensatz den dezimalen Code 13 (hexadezimal 0D) und wird mit "CR" abgekürzt, der Zeilenvorschub (auf Englisch "Line Feed" = LF) bekam den dezimalen Code 10 (hexadezimal 0A) und wird "LF" abgekürzt. Beide dieser Zeichen sind auch heute noch im aktuellen Unicode-Standard unter den gleichen numerischen Codepoints zu finden.
Manche Systeme nutzten die Unterscheidung zwischen CR und LF auch für diverse Texteffekte. Verwendete man bei der Druckersteuerung nur CR ohne LF ließ sich dadurch ein Wagenrücklauf ohne Zeilenvorschub realisieren. Die Schreibstelle konnte auf diese Weise an den Beginn einer bereits gedruckten Zeile gelangen und damit den vorhandenen Text mit anderen Zeichen überdrucken. So ließ sich zum Beispiel Text unterstreichen, durchstreichen oder fett schreiben. Auch diakritische Zeichen außerhalb des eigentlich verwendeten Zeichensatzes wurden auf diese Weise durch Überdruck beziehungsweise Kombination verschiedener Zeichen möglich. Ähnlich kann das im Unicode-Standard definierte Steuerzeichen RI (Reverse Line Feed = "umgekehrter Zeilenvorschub") mit dem Unicode-Codepoint U+008D verwendet werden.
Unicode, ASCII, EBCDIC, HTML-Entities und Escape-Sequenzen
Wie wir im letzten Abschnitt gesehen haben, gibt es zwischen den einzelnen Zeichensätzen neben vielen Gemeinsamkeiten auch gewisse Unterschiede. Aus diesem Grund möchten wir die betreffenden Zeichen in der nächsten Tabelle noch einmal gegenüberstellen:
Zeichen | Unicode Code Point | ASCII | EBCDIC | HTML Entity | Escape Sequenz | |||
CR | U+000D | 0D | 13 | 0D | 13 | 
 | | \r |
LF | U+000A | 0A | 10 | 25 | 37 | 
 | | \n |
CR LF | - | 0D 0A | 13 10 | 0D 25 | 13 37 | - | - | \r\n |
NEL/NL | U+0085 | - | 15 | 21 | … | … | \u0085 | |
VT | U+000B | 0B | 11 | 0B | 11 |  |  | \v |
FF | U+000C | 0C | 12 | 0C | 12 |  |  | \f |
LS | U+2028 | - | - | 
 | 
 | \u2028 | ||
PS | U+2029 | - | - | 
 | 
 | \u2029 |
Da der Unicode-Standard aus Kompatibilitätsgründen alle Zeichen aus dem ASCII-Zeichensatz mit identischen Codepoints als Block "Basis-Lateinisch" vollständig übernommen hat, sind alle Zeichen für Zeilenumbrüche aus dem ASCII-Zeichensatz wie der Zeilenvorschub LF, der Wagenrücklauf CR, der vertikale Tab VT sowie der Seitenvorschub FF sowohl im ASCII-Zeichensatz als genauso auch als gleichlautende Unicode-Codepoints definiert.
Zusätzlich definiert der Unicode-Standard noch die Codepoints U+0085, U+2028 und U+2029 als weitere Zeilenumbrüche, die im ASCII-Zeichensatz nicht enthalten sind. Von diesen echten Zeilenumbrüchen zu unterscheiden sind die Unicode-Codepoints U+2424 (Symbol for Newline), U+23CE (Return-Symbol), U+240D (Symbol for Carriage Return) sowie U+240A (Symbol for Line Feed), die zwar selber keinen Zeilenumbruch erzeugen, mit denen sich jedoch für den Nutzer sichtbare Glyphs erzeugen lassen, um die sonst unsichtbaren Zeilenumbruch-Zeichen zu visualisieren.
Auch der hauptsächlich von IBM Mainfraime Systems (Großrechnern) genutzte EBCDIC-Zeichensatz weist viele Parallelen zu ASCII auf. Auch wenn der Standard-EBCDIC-Zeilenumbruch das Zeichen NEL ist (hexadezimaler Code 15 / dezimaler Code 21), das selber keine ASCII-Entsprechung hat, definiert auch EBCDIC Codepoints für die Zeichen CR, LF, VT und FF. Nur LF ist von diesen vier Zeichen unter einem anderen, von ASCII abweichenden Codepoint in EBCDIC definiert (25/37 statt 0A/10).
Das zu EBCDIC-NL äquivalente Unicode-Zeichen ist NEL (Next Line) und hat den Unicode-Codepoint U+0085. Dieses Zeichen wurde auch deswegen zusätzlich zu CR und LF im Unicode-Standard definiert, um eine bidirektionale Konvertierung aus und in alle anderen Kodierungen zu ermöglichen. Hätten wir nur die Zeichen CR und LF im Unicode-Standard zur Verfügung, wäre dies nämlich nicht möglich: Wenn wir zum Beispiel einen EBCDIC-Text nach Unicode und wieder zurück konvertieren wollten, könnten wir in diesem Fall bei der Hinkonvertierung zunächst alle NEL-Zeilenumbrüche entweder in LF oder CR LF ändern. Bei der Rückkonvertierung kämen wir allerdings in eine Uneindeutigkeit, da EBCDIC einen Unterschied zwischen CR, LF und NL macht und es deswegen nicht mehr eindeutig wäre, ob unsere LF- und CR-Zeichen schon vorher LF und CR waren (und damit beibehalten werden müssten) oder sie ursprünglich ein NL waren (das rück-konvertiert werden müsste). Dadurch dass uns aber auch im Unicode-Standard die drei verschiedenen Zeichen CR, LF und NEL zur Verfügung stehen, ist eine Transformation ohne Informationsverlust möglich.
Weiterhin zeigt die Tabelle in ihren letzten beiden Spalten die HTML-Entities sowie die Escape-Sequenzen der einzelnen Zeichen. Die HTML-Entities können dafür verwendet werden, die jeweiligen Zeichen in einen HTML-Quelltext einzufügen. Die Tabelle zeigt die HTML-Entities sowohl in ihrer hexadezimalen als auch in ihrer dezimalen Schreibweise. Diese beiden Varianten führen zu dem gleichen Ergebnis und können daher austauschbar verwendet werden. Für das LF-Zeichen kann darüber hinaus die HTML-Entity 
 verwendet werden. In ähnlicher Weise sind auch die Escape-Sequenzen aus der letzten Spalte Platzhalter der genannten Zeichen. Die Escape-Sequenzen lassen sich zum Beispiel in regulären Ausdrücken oder in einigen Programmiersprachen als Alias beziehungsweise zum Einfügen der entsprechenden Zeilenumbruchzeichen nutzen. Mehr dazu im Abschnitt über Zeilenumbrüche im Programmcode.
Auf ASCII basierende 8-Bit-Kodierungen wie die Windows Codepages oder die Latin-Zeichensätze sind in der Tabelle nicht aufgeführt, da auch diese Zeichensätze alle ASCII-Zeichen 1:1 übernommen haben und daher der Spalte "ASCII" in der Tabelle entsprechen.
Nur der Vollständigkeit halber sollte weiterhin noch erwähnt werden, dass es neben dem gebräuchlichen und am häufigsten genutzten Unicode-Standard, der seine ersten Codepoints aus dem ASCII-Zeichensatz übernommen hat, auch einen alternativen Unicode-Standard namens UTF-EBCDIC gibt, der stattdessen weitestgehend auf dem EBCDIC-Zeichensatz aufbaut.
Byte-Repräsentationen in verschiedenen Kodierungen
Abhängig von der verwendeten Kodierung resultieren die genannten Unicode-Codepoints in unterschiedlichen Bytes innerhalb einer gespeicherten Datei. Eine Übersicht über die Bytefolgen der verschiedenen Zeilenumbruchtypen in den Kodierungen ASCII, UTF-7, UTF-8, UTF-16 Litte Endian und Big Endian sowie UTF-32 Litte Endian und Big Endian gibt die folgende Tabelle:
Zeichen | Unicode Code Point | ASCII | UTF‑7 | UTF‑8 | UTF‑16 LE | UTF‑16 BE | UTF‑32 LE | UTF‑32 BE |
CR | U+000D | 0D | 0D | OD | 0D 00 | 00 0D | 0D 00 00 00 | 00 00 00 0D |
LF | U+000A | 0A | 0A | 0A | 0A 00 | 00 0A | 0A 00 00 00 | 00 00 00 0A |
CR LF | - | 0D 0A | 0D 0A | 0D 0A | 0D 00 0A 00 | 00 0D 00 0A | 0D 00 00 00 0A 00 00 00 | 00 00 00 0D 00 00 00 0A |
NEL/NL | U+0085 | - | 2B 41 49 55 | C2 85 | 85 00 | 00 85 | 85 00 00 00 | 00 00 00 85 |
VT | U+000B | 0B | 2B 41 41 73 | 0B | 0B 00 | 00 0B | 0B 00 00 00 | 00 00 00 0B |
FF | U+000C | 0C | 2B 41 41 77 | 0C | 0C 00 | 00 0C | 0C 00 00 00 | 00 00 00 0C |
LS | U+2028 | - | 2B 49 43 67 | E2 80 A8 | 28 20 | 20 28 | 28 20 00 00 | 00 00 20 28 |
PS | U+2029 | - | 2B 49 43 6B | E2 80 A9 | 29 20 | 20 29 | 29 20 00 00 | 00 00 20 29 |
Typische 8-Bit-Kodierungen, die auf ASCII aufbauen, wie zum Beispiel die Windows-Codepages oder die Latin-Zeichensätze sind in der Tabelle nicht gesondert aufgeführt. Diese Kodierungen nutzen die selben Bytes wie ASCII, die entsprechend in der ASCII-Spalte zu finden sind. Auch viele andere ANSI-Codepages und Zeichensätze folgen dieser Konvention.
Wichtig sind die in dieser Tabelle aufgeführten Byte-Repräsentationen unter anderem für die Erkennung des Zeilenumbruchtyps von Dateien, der wir uns im Abschnitt über das Erkennen des Zeilenumbruchtyps einer Datei widmen.
Zeilenumbruchzeichen als Zeilentrenner oder als Markierung des Zeilenendes
Zeichen für Zeilenumbrüche lassen sich in zwei verschiedenen Weisen interpretieren, die beide ihre Fürsprecher und Vertreter haben: ein Zeilenumbruchzeichen kann entweder als Trennzeichen zwischen zwei Zeilen angesehen werden oder als Markierung eines Zeilenendes.
Schauen wir uns dazu das folgende Beispiel an, in dem "N" für das Zeilenumbruchzeichen steht:
abcNdefN
Den Inhalt einer solchen Datei könnten wir auf zwei verschiedene Weisen interpretieren:
- Falls wir das Zeilenumbruchzeichen als Trennzeichen zwischen zwei Zeilen interpretieren, hätte unser Beispiel drei Zeilen: die erste Zeile mit dem Inhalt "abc", die zweite Zeile mit dem Inhalt "def", gefolgt von einer dritten Zeile, die leer ist.
- Falls wir das Zeilenumbruchzeichen hingegen als Zeilen-Terminator interpretieren, kämen wir nur auf zwei Zeilen: die erste Zeile mit dem Inhalt "abc" und "N" als Markierung des Zeilenendes sowie die zweite Zeile mit dem Inhalt "def" und abermals "N" als Abschlusszeichen.
Es gibt sowohl Programme, die Zeilenumbruchzeichen als Separator ansehen als auch andere Programme, die Zeilenumbruchzeichen als Terminator interpretieren. Die Probleme, die daraus resultieren, liegen auf der Hand: Programme, die das Umbruchzeichen als Trennzeichen ansehen, interpretieren möglicherweise eine (leere) Zeile zu viel; Programme, die das Umbruchzeichen dagegen als Marker für das Zeilenende ansehen, haben möglicherweise Probleme, die letzte Zeile einer Datei zu lesen.
Eingabe von Zeilenumbruch-Zeichen
Der Systemzeilenumbruch lässt sich in der Regel am einfachsten mit der Enter-Taste eingeben. Eine Ausnahme ergibt sich für den Fall, dass die Eingabe innerhalb eines Editors erfolgt, der andere Zeilenumbruchtypen versteht und in dem entweder gerade an einer Datei mit systemfremdem Zeilenumbruchtyp gearbeitet wird oder die Einstellungen dieses Editors (oder eines anderen Programms) einen entsprechenden anderen Zeilenumbruchtyp vorsehen.
Die Eingabe der anderen Zeilenumbruchtypen ist etwas schwieriger: Einige Systeme und Texteditoren erlauben die Tastenkombination STRG + J für die Eingabe des LF-Zeichens. Weitere gebräuchliche Tastenkombinationen sind STRG + M für CR sowie STRG + K für VT (auf diese Weise kommt auch die Anzeige von ^M für CR zustande). Interpretieren wir CR und LF als Wagenrücklauf und Zeilenvorschub können wir dies über die Tasten Pos1 und Pfeil-Runter realisieren.
Innerhalb von HTML-Quelltext können die Zeilenumbruch-Zeichen darüber hinaus über ihre HTML-Entities eingefügt werden, die in der Tabelle im Abschnitt "Unicode, ASCII, EBCDIC, HTML-Entities und Escape-Sequenzen" aufgelistet sind. Weiterhin können wir die Zeichen mit der Tastenkombination ALT + Codepoint des Zeichens über das Num-Tastenfeld der Tastatur eingeben und in einigen Kontexten wie zum Beispiel in regulären Ausdrücken oder in vielen Programmiersprachen die Escape-Sequenzen der Zeichen nutzen, die ebenfalls in der genannten Tabelle für jedes der Zeichen aufgeführt sind. Mehr zu letzterem im Abschnitt über Zeilenumbrüche im Quellcode verschiedener Programmiersprachen.
Zeilenumbrüche durch Definition einer festen Zeilenlänge
Im Gegensatz zu den auf bestimmten Zeichendefinitionen basierenden Zeilenumbruchtypen, die im letzten Abschnitt vorgestellt wurden, kommen Textdateien mit einer fixen Zeilenlänge ganz ohne die Definition eines oder mehrerer Zeichen für einen Zeilenumbruch aus. Stattdessen basiert jede Zeile einer solchen Datei auf einer zunächst frei wählbaren Zeilenlänge, die jedoch innerhalb der Datei konstant gehalten wird. In der Datei selber werden dann alle Zeilen einfach hintereinander weg geschrieben und gegebenenfalls durch ein geeignetes Füllzeichen auf die geforderte Länge gebracht.
Der Inhalt einer solchen Datei (hier beispielhaft mit einer festen Zeilenlänge von vier Zeichen) kann dann zum Beispiel so aussehen:
ABCDABC ABCD
Ein Programm, das die für die Datei verwendete Zeilenlänge kennt und darstellen kann, kann diesen Inhalt dann folgendermaßen interpretieren:
ABCD
ABC
ABCD
Da die zweite Zeile nur drei Zeichen enthält, haben wir hier ein Leerzeichen als Füllzeichen verwendet. Hätten wir das nicht getan, wäre das "A" aus der dritten Zeile an das Ende der zweiten Zeile gerutscht.
Verbreitung und Anwendungsbereiche
Dateien mit einer festen Zeilenlänge sind deutlich weniger weit verbreitet als Dateien, die ihre Zeilenumbrüche mit einem festgelegten Zeichen für einen Umbruch realisieren. Der Hauptgrund, der gegen die Verwendung einer festen Zeilenlänge spricht, ist die mangelnde Flexibilität. Schließlich haben die wenigsten Texte in jeder Zeile gleich viele Zeichen.
Dennoch gibt es einige nützliche Anwendungsbereiche für solche Dateien, zum Beispiel im Falle von CSV-Daten oder anderen Datensätzen, deren Werte in jeder Zeile alle die gleiche Länge haben, so dass zusätzliche Zeichen für Zeilenumbrüche keinen weiteren Informationsgewinn für die Interpretation derartiger Dateien darstellen würden, sodass diese Zeichen entsprechend eingespart werden können (insbesondere in Anwendungen oder Umgebungen in denen Speicher gespart werden muss).
Feste Zeilenlänge als Systemzeilenumbruch
Als Systemzeilenumbruch wurde die Feste Zeilenlänge lediglich auf einigen der ersten Großrechner genutzt. Üblich auf solchen Systemen waren damals meist feste Zeilenlängen von 72 oder 80 Zeichen. Diese Anzahl war den davor verwendeten Lochkarten nachempfunden, die üblicherweise auch 80 Spalten pro Karte umfassten, von denen die Spalten 73 bis 80 häufig für Sequenznummern verwendet wurden. Einige dieser Systeme kodierten Zeilen mit mehr als 80 Zeichen indem ein Carriage-Zeichen wie # als erstes Zeichen an den Anfang der nächsten zu verknüpfenden Zeile gestellt wurde.
Ebenfalls ohne Zeichen für einen Zeilenumbruch kommen auf Records basierende Dateisysteme aus, wie sie zum Beispiel von den Betriebssystemen OpenVMS, RSX-11 oder diversen neueren Großrechnern genutzt werden. Solche Systeme speichern Textdateien als je ein Record pro Zeile. Jeder dieser Records enthält ein Längenfeld am Zeilenanfang, in dem individuell die Länge der jeweiligen Zeile gespeichert ist. Dadurch ist kein zusätzlicher Zeilenbegrenzer in Form eines Steuerzeichens notwendig, da das lesende Programm durch diese Information bereits weiß, nach wie vielen Zeichen die Zeile endet beziehungsweise wie viele Zeichen eingelesen werden müssen, um eine Zeile zu lesen. Auch wenn die Speicherung auf diese Weise ohne Zeichen für einen Zeilenumbruch auskommt, sind die verwendeten Record Management Systeme in der Regel dazu fähig, einem anfragenden Programm die angefragten Zeilen nach Bedarf auch mit einem Zeilentrennerzeichen zu übergeben.
Zeilenumbrüche im HTML-Quelltext und anderen Auszeichnungssprachen
Neben den zeichenbasierten Zeilenumbruchtypen und den Zeilenumbrüchen durch Definition einer festen Zeilenlänge, die wir uns in den letzten beiden Abschnitten angesehen haben, gibt es die weitere Möglichkeit, Zeilenumbrüche durch eine Auszeichnungssprache (in Englisch "markup") zu realisieren.
Zeilenumbrüche im HTML-Quelltext
Zu den bekanntesten Vertretern der Auszeichnungssprachen zählt der auf XML basierende Quelltext von HTML, die Basis von Internetseiten, wie wir sie heute kennen. Die Realisierung von Zeilenumbrüchen im HTML-Quelltext und in anderen ähnlichen Auszeichnungssprachen stellt insofern eine Besonderheit dar, da Zeilenumbrüche dabei auf zwei verschiedenen Ebenen auftreten können: Im Quelltext selber können beliebige zeichenbasierte Zeilenumbrüche wie CRLF oder LF enthalten sein, die aber im Verborgenen bleiben, da die letztendliche Darstellung von Zeilenumbrüchen auf der später sichtbaren Internetseite im Browser allein auf der Grundlage der textbasierten HTML-Tags und anderer Formatierungen wie CSS-Stylesheets beruht.
Um dies zu verdeutlichen, möchten wir uns zwei HTML-Quelltexte als Beispiel ansehen. Einerseits den folgenden HTML-Quelltext:
<h1>Überschrift</h1><p>Erster Absatz</p><p>Zweiter<br>Absatz</p>
Andererseits diesen Quelltext:
<h1>Überschrift</h1>
<p>Erster Absatz</p>
<p>Zweiter<br>
Absatz</p>
Wie wir sehen enthält das erste Beispiel keinerlei "sichtbare" Zeilenumbrüche, während im zweiten Beispiel hinter jedem Sinnabschnitt sowie innerhalb des zweiten Absatzes ein Zeilenumbruch gesetzt ist. Dennoch führen beide Quelltexte zu exakt derselben Darstellung im Browser. Für die Interpretation des Quelltextes spielt so genannter Whitespace wie zusätzliche Leerzeichen, Tabs oder eben auch Zeilenumbrüche nämlich keine Rolle.
Entscheidend ist in diesem Beispiel-Quelltext nur, dass wir einen Text in einen h1-Tag ("Überschrift 1" von englisch "heading") gesetzt haben und zwei weitere Texte in einen p-Tag (Absatz von englisch "paragraph"). Standardmäßig (man kann dieses Verhalten auch überschreiben) werden diese Tags beide so interpretiert, dass hinter ihnen ein Zeilenumbruch in Form eines Absatzes eingefügt wird. Das gleiche gilt auch für Tags wie h2 (Überschrift 2), h3 (Überschrift 3), li (Listenelemente) oder dem klassischen HTML-Zeilenumbruch br (einfacher Umbruch von englisch "break"), mit dem wir den zweiten Absatz umgebrochen haben. Durch andere Tags wie zum Beispiel fomatierenden Tags wie b (bold / fett) oder i (italic / kursiv) werden in der Darstellung keine automatischen Umbrüche eingefügt.
Klassische, nicht auf Tags basierende Zeilenumbrüche im Quelltext können dagegen unabhängig von der Darstellung im Browser verwendet werden, zum Beispiel um den Quelltext zu gliedern und besser lesbar zu machen. Dabei können diese später im Browser unsichtbaren Zeilenumbrüche sowohl in Form von zeichenbasierten Zeilenumbrüchen verwendet werden als auch zum Beispiel über sogenannte HTML-Entities eingefügt werden, die im Abschnitt über HTML-Entities aufgelistet sind.
Verhalten durch den pre-Tag überschreiben
Überschreiben lässt sich dieses Verhalten der unsichtbaren zeichenbasierten Zeilenumbrüche im Quelltext durch den HTML-Tag "pre" sowie durch das CSS-Style-Attribute "white-space:pre". Die Zeilenumbrüche und sonstiger Whitespace wie Leerzeichen von Quelltext, der sich innerhalb eines pre-Tags oder innerhalb von Tags mit der CSS-Eigenschaft "white-space" mit dem Wert "pre" befinden, werden dadurch als solche im Browser ausgegeben:
<pre>Zeile 1
Zeile 2</pre>
<span style="white-space: pre">Zeile 3
Zeile 4</span>
Dieser Quelltext erzeugt im Browser vier umgebrochene Zeilen obwohl die Zeilenumbrüche lediglich mittels normalerweise unsichtbarem "Whitespace" in den Quelltext geschrieben wurden. Der Zeilenumbruch zwischen der ersten und der zweiten Zeile wird durch den pre-Tag erzeugt, der Zeilenumbruch zwischen der dritten und vierten Zeile durch die CSS-Eigenschaft des umschließenden span-Elements.
Zeilenumbrüche in LaTeX, Markdown, RTF, Creole, PostScript, BBCode und AsciiDoc
Andere gebräuchliche Auszeichnungssprachen sind zum Beispiel LaTeX, Markdown, RTF, Creole und PostScript, in denen jeweils eine andere Syntax zur Auszeichnung von Zeilenumbrüchen verwendet wird:
- TeX / LaTeX liefert uns drei Möglichkeiten, einen Zeilenumbruch auszuzuzeichnen: Mit zwei Schrägstrichen "\\", mit "\newline" oder mit "\hfill \break".
- Markdown verwandelt Leerzeilen in Absätze und zwei oder mehr Leerzeichen am Ende einer Zeile in einen Zeilenumbruch.
- Im Rich Text Format (RTF) können Absätze mit "\par" (von Paragraph) und einfache Zeilenumbrüche mit "\line" eingefügt werden.
- Creole verwendet "\\linebreak" um Zeilenumbrüche auszuzeichnen.
- In der Seitenbeschreibungssprache PostScript verhält es sich etwas anders: Hier müssen wir für die Textausgabe in einer neuen Zeile vor der Spezifikation des Textes mit dem "moveto"-Befehl an die gewünschte Ausgabeposition wechseln (im Falle eines Zeilenumbruchs also an die Stelle unserer Seite, an der die neue Zeile beginnen soll).
In Auszeichnungssprachen wie BBCode oder AsciiDoc werden dagegen trotz der Möglichkeit anderer Auszeichnungen (wie zum Beispiel "[b]wort[/b]" beziehungsweise "*wort*" für fetten Text) Zeilenumbrüche aus dem Quelltext genauso auch in das Ergebnis übernommen. In diesen Auszeichnungssprachen wird insofern der zeichenbasierte Zeilenumbruch (ähnlich wie in Markdown) selber als Markup verwendet.
Voraussetzungen für die Nutzung von Auszeichnungssprachen
Voraussetzung für die Nutzung von Auszeichnungssprachen wie HTML, TeX / LateX, Markdown, RTF, Creole, PostScript, BBCode oder AsciiDoc ist natürlich, dass die verwendeten Auszeichnungen, Befehle und Tags bekannt sein müssen. Ohne zu wissen, wie bestimmtes Markup gemeint ist, verwendet oder interpretiert werden soll, ist eine Darstellung nicht möglich.
Zeilenumbrüche im Quellcode verschiedenener Programmiersprachen
Auch im Quellcode von Programmierungen sind wir mit dem Problem konfrontiert, dass wir - ähnlich wie beim HTML-Quelltext - einen Unterschied machen müssen zwischen dem Quellcode selber sowie dem, was später real vom ausgeführten und möglicherweise kompilierten Programm angezeigt werden soll. Dabei gilt es den Spagat zu meistern zwischen einem möglichst gut durch Menschen lesbaren Code, der sich jedoch nicht negativ auf das Programm auswirken darf.
Gelöst wurde dieser Spagat auch hier, indem viele Programmiersprachen strikt zwischen den Zeilenumbrüchen im Quellcode und den Zeilenumbrüchen, die später das Programm ausgibt, unterscheiden: Im Quellcode können in der Regel je nach Betriebssystem die üblichen zeichenbasierten Zeilenumbrüche verwendet werden, während für die im Programm ausgegebenen Zeilenumbrüche eine Auszeichnungssprache existiert, die sich von Programmiersprache zu Programmiersprache unterscheiden kann. Einige Beispiele dafür sind in der folgenden Tabelle gelistet:
Sprache | Expliziter Zeilenumbruch | Systemzeilenumbruch |
C | char s[] = "-\r\x0A-"; | char s[] = "\n"; |
C++ | std::string s = "-\r\x0A-"; | std::string s = "\n"; |
C# | string s = "-\r\n-"; | string s = Environment.NewLine; |
Java | String s = "-\r\n-"; | String s = System.lineSeparator(); String s = "-%n-"; |
JavaScript / TypeScript | var s = "-\n-"; | |
Delphi | var s: string; s := '-' + #13#10 + '-'; | var s: string; s := sLineBreak; |
Lazarus / FreePascal | var s: string; s := '-' + #13#10 + '-'; | var s: string; s := LineEnding; |
PHP | $s = "-\r\n-"; | $s = PHP_EOL; |
Python | s = "-\r\n-" | s = os.linesep |
Perl | my $s = "-\r\x0A-"; | my $s = "\n"; |
Haskell | "-\CR\LF-" :: [Char] | "\n" :: [Char] |
Visual Basic | Dim s1 As String = "-" & vbCrLf & "-"; Dim s2 As String = "-" & vbCr & "-"; Dim s3 As String = "-" & vbLf & "-"; | Dim s1 As String = System.Environment.NewLine; Dim s2 As String = vbNewLine; (deprecated) |
SQL | UPDATE tab SET col = '-' + CHAR(13) + CHAR(10) + '-'; |
Wie die Tabelle zeigt, können wir in den meisten Programmiersprachen zwei verschiedene Herangehensweisen nutzen, um einen Zeilenumbruch einzufügen:
- Entweder wir definieren unseren Zeilenumbruch explizit über dessen Zeichen, wodurch wir fest auf einen bestimmten Zeilenumbruchtyp festgelegt sind (die Beispiele zeigen jeweils zwei Zeilen mit dem Inhalt "-" unter Verwendung des Windows-Zeilenumbruchs \r\n beziehungsweise 0D 0A, 13 10 oder \CR\LF - einen Unix-Zeilenumbruch können wir in der gleichen Weise erzeugen, indem wir \r, 0D, 13 oder \CR weglassen und nur \n, 0A, 10 oder \LF schreiben),
- oder wir definieren unseren Zeilenumbruch plattformunabhängig über bestimmte Variablen, Konstanten oder Funktionen, die uns die jeweilige Programmiersprache zur Verfügung stellt. Letzteres hat den Vorteil dass wir uns keine Gedanken über das System machen müssen, auf dem unser Programm ausgeführt wird, da wir auf diese Weise automatisch den passenden System-Zeilenumbruchtyp erhalten (falls wir das möchten).
In den nächsten beiden Abschnitten möchten wir näher auf beide Varianten und deren Fallstricke eingehen.
Expliziter Zeilenumbruch
In vielen Programmiersprachen wie C, C++, C#, Java, PHP, Python, Perl oder Haskell können die im Abschnitt "Zeichenbasierte Zeilenumbruchtypen" vorgestellten Escape-Sequenzen wie \r und \n für die Einfügung eines Zeilenumbruchs in einen String verwendet werden. Grundsätzlich steht dabei \r für einen Carriage Return (CR, U+000D, Wagenrücklauf) und \n für einen Line Feed (LF, U+000A, Zeilenvorschub), wodurch sich die Zeilenumbrüche für die verschiedenen Systeme erzeugen lassen.
Je nach Programmiersprache sind bei der Verwendung von \r und \n jedoch noch die folgenden Aspekte und Besonderheiten zu beachten:
- In einigen Programmiersprachen wie PHP und Perl können wir Strings sowohl mit einfachen ('text') als auch mit doppelten Anführungszeichen ("text") definieren. Escape-Sequenzen wie \r und \n werden in diesen Sprachen jedoch nur automatisch ersetzt, sofern sie in doppelten Anführungszeichen vorkommen. Demnach würde "-\r\n-" einen Zeilenumbruch zwischen den beiden Zeichen "-" und "-" erzeugen während '-\r\n-' die Zeichen als solche beibehält. In anderen Programmiersprachen wie zum Beispiel JavaScript, TypeScript und Python spielt es keine Rolle, ob wir einfache oder doppelte Anführungszeichen verwenden. JavaScript und Python interpretieren sowohl "\n" als auch '\n' als Zeilenumbruch. In C, C++, C#, Java und Haskell stellt sich diese Frage dagegen erst gar nicht: In diesen Programmiersprachen werden für Strings nur doppelte Anführungszeichen verwendet während einfache Anführungszeichen Chars vorbehalten sind.
- Obwohl JavaScript und TypeScript sowohl \r als auch \n verstehen, sollten wir dennoch mit einer gemeinsamen Verwendung dieser beiden Zeichen vorsichtig sein: Auch auf Windows-Computern führt ein alert("-\r\n-") zur Ausgabe von nicht nur einem sondern zwei Zeilenumbrüchen. Das plattformunabhängige JavaScript (und TypeScript) interpretiert sowohl \r als auch \n als einen eigenen Zeilenumbruch. Um nur einen Zeilenumbruch zu erzeugen, sollten wir \n verwenden, also zum Beispiel alert("-\n-"). Trotzdem kann Text durchaus auch in diesen Sprachen die \r\n-Variante enthalten. Die sollte man zum Beispiel bei der Verarbeitung von User-Input, der von einem Windows-Rechner stammt, berücksichtigen. Auch LS- und PS-Umbrüche werden im Input von JavaScript als Zeilenumbrüche akzeptiert, nicht jedoch NEL, welches als Leerzeichen interpretiert wird. Weiterhin sollten wir beachten dass es, falls wir mit unserem JavaScript- oder TypeScript-Code HTML erzeugen möchten, nicht auf die zeichenbasierten Zeilenumbrüche \r oder \n ankommt, sondern auf die richtigen HTML-Tags, die wir im Abschnitt über Zeilenumbrüche in HTML beschrieben haben.
- Java unterscheidet zwischen \r, \n und %n. %n steht plattformunabhängig für den System-Zeilenumbruch (also \r\n falls das Programm unter Windows ausgeführt wird, \n falls das Programm unter Unix, Linux, macOS etc. ausgeführt wird und so weiter), während \n explizit für das Zeichen U+000A (LF) steht (also ausschließlich für den Unix-Zeilenumbruch) und \r explizit für das Zeichen U+000D (CR) steht. Javas readLine() akzeptiert sowohl CR, LF als auch CRLF als Zeilenende. Beim Einlesen von EBCDIC-Text wird das EBCDIC-Zeichen NL jedoch nicht auf NEL (U+0085) angebildet sondern auf LF (U+000A).
- In C, C++, Perl und Haskell stehen \r und \n nicht automatisch immer für genau die Zeichen CR (U+000D) und LF (U+000A). Abhängig ist dies vom verwendeten Modus: Wird in eine Datei geschrieben oder eine Datei geöffnet, kann dies entweder im Textmodus oder im Binärmodus erfolgen. Im Binärmodus verhalten sich \r und \n wie erwartet. Im Textmodus dagegen steht (ausgehend vom C-Standard) bereits die Escape-Sequenz \n alleine für einen vollständigen Zeilenumbruch, der abhängig vom System ist. Dies bedeutet, dass schon die alleinige Verwendung von \n im Textmodus unter Windows zur Ausgabe eines vollständigen CRLF-Zeilenumbruch führt, \n alleine produziert damit also den eigentlich von \r\n erwarteten Output. Verwenden wir stattdessen \r\n würde dies unter Windows entsprechend zu einer Ausgabe von CRCRLF führen und CR damit verdoppeln (\r wird zum ersten CR, danach wird \n zum zweiten CR und LF). Auf Unix-Systemen dagegen würde \r\n zu einer Ausgabe von CRLF führen, da ein vollständiger Unix-Zeilenumbruch nur aus dem Zeichen LF besteht. Aus diesem Grund nutzen die Beispiele für C, C++, Perl und Haskell explizit \x0A beziehungsweise \CR statt \n, obwohl \n unter Unix in allen Fällen und unter Windows im Binärmodus auch funktionieren und das Zeichen 0A (LF) ausgeben würde. Das tückische: Diese Problematik fällt erst auf, wenn ein Programm unter Windows ausgeführt wird. Wird auf einem Unix-System entwickelt und getestet, existiert die Problematik nicht und kann daher nicht auffallen.
- In PHP, Python, C# und Java ist dagegen garantiert, dass \r immer für U+000D und \n immer für U+000A steht beziehungsweise dass folglich \r\n immer dem Windows-Zeilenumbruch CRLF entspricht. In diesen Sprachen erfolgt keine automatische Umwandlung.
Etwas anders verhält es sich in Delphi, Lazarus, Visual Basic und SQL. Statt den Escape-Sequenzen \r und \n können wir in Visual Basic die Konstanten vbCr und VbLf für die Zeichen CR und LF verwenden. Zusätzlich gibt es die Konstante vbCrLf für den Windows-Zeilenumbruch beziehungsweise für beide Zeichen zusammen. In Delphi, FreePascal und Lazarus können wir die Zeichen direkt über ihre Zeichen-Codes #13 (CR) und #10 (LF) einfügen. Ähnlich verhält es sich in der Datenbanksprache SQL, in der wir in ähnlicher Weise CHAR(13) und CHAR(10) nutzen können, um die entsprechenden Zeichen zu erzeugen.
Variablen, Konstanten und Funktionen für den Systemzeilenumbruch
Neben dieser expliziten Definition von Zeilenumbrüchen stellen uns die meisten Programmiersprachen Variablen, Konstanten oder Funktionen zur Verfügung, mit denen sich plattformunabhängig der jeweilige Systemzeilenumbruch einfügen lässt:
- Ein Beispiel dafür ist die Konstante "LineEnding" in Lazarus und Free Pascal ("sLineBreak" ist das Äquivalent in Delphi). Je nachdem auf welchem System wir unser Programm kompilieren, enthält diese Konstante den passenden Zeilenumbruch. Kompilieren wir unser Programm für Windows, enthält "LineEnding" die Zeichen CR und LF (also den Windows-Zeilenumbruch). Kompilieren wir unser Programm dagegen stattdessen für macOS oder Linux, enthält "LineEnding" den unter macOS und Linux genutzten Unix-Zeilenumbruch LF. Lazarus lässt uns also die Wahl entweder #13#10 für einen fixen Zeilenumbruch zu schreiben oder mit "LineEnding" variabel zu bleiben.
- Ähnliche Konzepte gibt es auch in anderen Programmiersprachen. PHP stellt uns beispielsweise die Konstante PHP_EOL für denselben Zweck zur Verfügung, während die Konstante in Visual Basic vbNewLine heißt.
- Wie schon im letzten Abschnitt näher erläutert können wir in den Programmiersprachen C, C++, Perl und Haskell die Escape-Sequenz /n für den Systemzeilenumbruch verwenden, die in den meisten anderen Sprachen nur für das Zeichen LF steht.
- Andere Sprachen stellen uns Funktionen zur Verfügung, um den Systemzeilenumbruch zu erhalten: In Python geht dies beispielsweise mit os.linesep, in C# können wir für den gleichen Zweck Environment.NewLine nutzen.
- Einige Sprachen stellen uns auch gleich mehrere Möglichkeiten zur Verfügung: Zum Beispiel können wir in Java den System-Zeilenumbruch entweder mit der Escape-Sequenz %n (statt \n) einfügen oder die Funktion System.lineSeparator() nutzen. Ähnlich verhält es sich mit Visual Basic, wo uns sowohl vbNewLine als auch System.Environment.NewLine zur Verfügung stehen (vbNewLine wurde allerdings inzwischen als deprecated markiert und sollte nicht mehr verwendet werden).
- JavaScript, TypeScript und SQL kennen dagegen aufgrund ihrer Optimierung auf plattformunabhängige Verwendbarkeit kein natives Konzept zur Ermittlung des Systemzeilenumbruchs.
Auf diese Weise können wir selber entscheiden, ob wir explizit einen bestimmten Zeilenumbruchtyp nutzen möchten (zum Beispiel weil unser Ziel ist, Dateien mit genau diesem Zeilenumbruchtyp zu speichern) oder ob unser Programm automatisch den passenden Systemzeilenumbruch einsetzen soll (zum Beispiel weil unser Programm auf verschiedenen Systemen eine jeweils passende Ausgabe erzeugen soll).
Netzwerkprotokolle
Auch in Netzwerkprotokollen spielt die Verwendung des richtigen Zeilenumbruchtyps eine große Rolle. Viele dieser Netzwerkprotokolle wie zum Beispiel HTTP, SMTP, FTP und IRC sind textbasiert und nutzen den Zeilenumbruchtyp CRLF für ihre zeilenweise übermittelten Requests.
Einige Programme halten sich strikt an diesen Standard und verweigern entsprechend die Verarbeitung von Requests, die einen anderen Zeilenumbruchtyp wie zum Beispiel LF verwenden (wie zum Beispiel qmail). Andere Programme sind toleranter in der Verarbeitung oder nutzen sogar fälschlicherweise stets den Systemzeilenumbruchtyp für ihre Requests, was zu Problemen in der Kommunikation mit Systemen führen kann, die den Standard strenger umsetzen. Einige dieser Probleme resultieren auch aus der Verwendung des C-typischen \n welches, wie wir im letzten Abschnitt gesehen haben, in Programmiersprachen wie C, C++, Perl und Haskell je nach Betriebssystem und Modus, entweder als das korrekte CRLF oder das inkorrekte LF aufgelöst werden kann.
Um diese Probleme zu vermeiden empfehlen einige Protokolle inzwischen auch andere Zeilenumbruchtypen als CRLF anzuerkennen. Mit der weiteren Verwendung von CRLF sind wir dennoch auf der richtigen Seite, da wir nicht wissen, welches möglicherweise veraltete Programm auf der Gegenseite verwendet wird.
Erkennung des Zeilenumbruchtyps einer Datei
Im Gegensatz zur Kodierung von Textdateien, deren "Encoding-ID" wir für bestimmte Unicode-Kodierungen als Erkennungszeichen in der Form einer sogenannten Byte Order Mark (BOM) an den Beginn einer Textdatei schreiben können, ist es bei der Erkennung des Zeilenumbruchtyps einer Datei nicht so einfach. Für den verwendeten Zeilenumbruchtyp einer Datei gibt es nichts vergleichbares was uns den Zeilenumbruchtyp auf ähnliche Weise signalisieren könnte wie die BOM. Wenn wir eine unbekannte Textdatei vor uns haben, bleiben uns daher lediglich einige Faustregeln, um den Zeilenumbruchtyp dieser Datei zu bestimmen.
Ein erstes Indiz liefert das Betriebssystem, auf dem die Textdatei erstellt wurde: Falls die Datei auf einem Windows-Rechner ihren Ursprung fand, ist der Windows-Zeilenumbruch CR LF wahrscheinlich. Wurde die Datei dagegen auf einem aktuellen Mac oder unter Linux erstellt, verwendet die Datei vermutlich einen Zeilenumbruch vom Unix-Typ LF. Jedoch kann es sich bei dieser Art von Einordnung allenfalls um eine Daumenregel handeln, da es zum Beispiel genug Texteditoren für Windows gibt, die zwar in ihrer Standardeinstellung den Windows-Zeilenumbruch voreingestellt haben mögen, mit denen es aber genauso auch möglich ist, Dateien unter Verwendung beliebiger anderer Zeilenumbruchtypen zu speichern. Darüber hinaus könnte es auch gänzlich unklar sein, von welchem System eine Datei überhaupt stammt.
Aus diesem Grund sollte man sich bei der Interpretation einer Textdatei unbekannten Ursprungs nicht auf derartige Vermutungen verlassen sondern versuchen, eine Entscheidung aufgrund der uns bekannten Bytes der Datei zu treffen. Dabei kann man zum Beispiel folgendermaßen vorgehen:
- Zeilenumbrüche zählen: In einem ersten Schritt sollten wir die Bytes beziehungsweise die Codepoints der Zeichen der Datei durchgehen und anschließend schauen, welche Art von Zeilenumbruch zu unserem durch diese Vorgehensweise ermittelten Profil passen könnte. Enthält unsere Datei beispielsweise jede Menge Codepoints vom Typ $0A (LF) jedoch keinen einzigen Codepoint vom Typ $0D (CR), so handelt es sich sehr wahrscheinlich um eine Textdatei mit dem Unix-Zeilenumbruchtyp LF. Kommen $0D und $0A dagegen genau gleich häufig vor und zusätzlich noch in einer Kombination der Art, dass jedem $0D ein $0A folgt, haben wir mit großer Wahrscheinlichkeit eine Datei mit dem Windows-Zeilenumbruchtyp CRLF vorliegen. In der gleichen Weise können wir auch für jeden anderen der in Frage kommenden Zeilenumbruchtypen vorgehen (eine Übersichtstabelle möglicher Bytefolgen finden Sie im Abschnitt über die Byte-Repräsentationen der Zeilenumbruchzeichen in verschiedenen Kodierungen).
- Kein Fund: Falls wir in unserer Datei unabhängig vom Typ kein einziges Zeichen gefunden haben, das in einem Zeilenumbruch vorkommen könnte oder auf die Verwendung eines bestimmten Typs hindeutet, könnte dies zwei Gründe haben. Entweder enthält unsere Datei gar keinen Zeilenumbruch sondern besteht lediglich aus einer einzigen Zeile oder es handelt sich um eine Datei, die die fixe Zeilenlänge als Zeilenbegrenzung verwendet. Trifft der zweite Fall zu, können wir zwar versuchen, eine mögliche fixe Zeilenlänge aufgrund der Dateistruktur zu erraten (zum Beispiel durch wiederkehrende Muster), jedoch wird es ohne Informationen darüber, welche fixe Zeilenlänge für die Datei gewählt wurde, sehr schwierig. Auch aufgrund der geringen Verbreitung von Textdateien mit fixer Zeilenlänge sollten wir im Zweifel in solch einem Fall zum bevorzugten Zeilenumbruch des Systems, auf dem wir die Datei öffnen (für eine weitere Bearbeitung der Datei), neigen.
- Uneindeutige Zählung: Ein weiteres Problem kann sich ergeben, wenn unsere Zählung kein eindeutiges Ergebnis liefert. Zum Beispiel könnte unsere Datei sowohl CR- als auch LF-Zeichen enthalten, jedoch nicht gleich viele. Damit kann unsere Datei weder eindeutig als Windows-Textdatei eingeordnet werden (dafür müssten gleich viele CR und LF in der Datei vorkommen), noch kann die Datei eindeutig dem CR- oder LF-Zeilenumbruch zugeordnet werden (dafür dürfte die jeweils andere Art nicht in der Datei vorkommen). Wir behandeln diesen Sonderfall im Abschnitt "Dateien mit gemischten Zeilenumbrüchen" dieses Artikels.
Zum Glück müssen wir die hier beschriebene Arbeit natürlich nur dann leisten, wenn wir selber ein Programm programmieren möchten, das mit allen Arten von Textdateien umgehen können soll. Ein Programm, dass dies bereits leisten kann, ist der TextKonverter: Standardmäßig arbeitet der TextKonverter mit der Einstellung "Zeilenumbruchtyp" > "Automatische Erkennung", was bedeutet, dass der TextKonverter die hier beschriebene Analyse Ihrer Dateien automatisch vornimmt und Sie davon gar nichts mitbekommen. Dennoch ist es mit dem TextKonverter natürlich auch möglich, diese Voreinstellung zu ändern und Dateien mit jeder beliebigen anderen Art von Zeilenumbruchtyp einzulesen oder zu speichern. Alle hier in diesem Artikel vorgestellten Zeilenumbruchtypen sind genauso verwendbar wie eine fixe Zeilenlänge oder auch einzelne oder mehrere beliebige benutzerdefinierte Zeichen oder Codepoints als Zeilenumbruch.
Probleme beim Austausch von Dateien
Aus den unterschiedlichen Kodierungen für den Zeilenumbruch erwachsen große Probleme beim Austausch von Dateien zwischen verschiedenen Systemen.
Die Probleme können dabei vielfältiger Natur sein:
- Eine unter Linux erstellte Datei scheint unter Windows zum Beispiel plötzlich keine Zeilenumbrüche mehr zu haben, da Windows ein weiteres Zeichen für einen vollständigen Zeilenumbruch erwartet als Linux es in die Datei geschrieben hat: Die gesamte Datei wird so als eine einzige lange Zeile dargestellt. Ähnlich verhält es sich, wenn wir versuchen, mit einem Texteditor von Windows eine Datei zu öffnen, die auf einem Mac oder einem anderen Unix-System erstellt wurde (vorausgesetzt der Editor versteht diese Art von Zeilenumbruch nicht).
- Anders herum können auf Windows erstellte Textdateien auf Unix-Systemen zur Verdoppelung aller Zeilenumbrüche führen, da manche Unix-Editoren sowohl CR als auch LF als einen einzelnen eigenen Zeilenumbruch interpretieren obwohl diese beide Zeichen unter Windows gemeinsam als ein Zeilenumbruch gelten. Einige Editoren stellen den zusätzlichen Zeilenumbruch auch als ^M oder <cr> am Ende jeder Zeile dar. Begünstigt wird das Problem der doppelten Zeilenumbrüche auf macOS-Systemen auch aus historischen Gründen: Da das Vorgängersystem Mac OS Classic bis Version 9 noch das Zeichen CR statt das heutige LF als Zeilentrenner nutzte, interpretieren viele moderne macOS-Programme noch heute neben LF auch das Zeichen CR als vollständigen Zeilenumbruch.
- Verwenden wir dagegen Dateien mit einer fixen Zeilenlänge, müssen wir dem Empfänger einerseits die Anzahl der Zeichen pro Zeile mitteilen, andererseits muss sichergestellt sein, dass unser Empfänger die Datei überhaupt öffnen kann, da die wenigsten Programme Textdateien fester Zeilenlänge unterstützen.
- Kompliziert kann es auch werden, wenn es sich um Dateien handelt, die einen der weniger gebräuchlichen Zeilenumbruchtypen verwenden wie zum Beispiel VT, FF, NEL, LS oder PS. Der Standard-Texteditor von Windows "Editor" erkannte vor Windows 11 beispielsweise keinen dieser Zeilenumbruchtypen und interpertierte NEL gemäß dem gleichlautenden Windows-Codepage-Codepoint 85 gerne als Ellipse-Zeichen (…). Erst mit Windows 11 (oder auch mit dem Update 1803 für Windows 10) wurde der Editor überarbeitet und erkennt inzwischen all diese Zeilenumbruchtypen bis auf NEL. Vor dieser Änderung hat der Windows Editor nicht einmal den weit verbreiteten aber systemfremden Unix-Zeilenumbruch LF erkannt. Der Standard-Linux-Texteditor der GNOME-Desktop-Umgebung (Ubuntu, Fedora, Debian, Suse) "gedit" erkennt immerhin LS und PS, jedoch nicht VT, FF und NEL. Lediglich der Default-Texteditor "TextEdit" von macOS erkennt neben den häufig verwendeten Umbruchtypen CR, LF und CRLF auch all diese zusätzlichen vom Unicode-Standard geforderten Zeilenumbruch-Zeichen VT, FF, NEL, LS und PS korrekt.
- Bei historischen Zeilenumbruchtypen wie RS, EOL oder Sinclair ist gar nicht erst zu erwarten, dass ein normaler Texteditor die Dateien von sich aus ohne Zusatzeinstellungen erkennt.
- Falls eine Textdatei von einem anderen System nicht einfach nur in einem Texteditor angezeigt werden soll sondern zum Beispiel als Konfigurationsdatei oder Datensatz dient, kann es passieren, dass das betreffende Programm die Datei gar nicht erst erkennt oder falsch interpretiert. Hinzu kommt, dass derartige Fehler manchmal erst spät auffallen oder die betroffenen Programme schwer zu interpretierende Fehlermeldungen ausgeben.
- Erschwerend kommt hinzu, dass die Vorgehensweise, wie Programme mit fremden Zeilenumbruchtypen umgehen, sehr unterschiedlich ausfallen kann. Einige Programme wie zum Beispiel Browser, die naturgemäß wie vielleicht keine andere Programmklasse Textdateien beliebiger Systeme verarbeiten müssen, da bei einer Webseite völlig unklar ist, auf welchem System der zugrunde liegende Quelltext erstellt wurde, akzeptieren in der Regel jedes der genannten Zeichen als Zeilenumbruch. Andere Programme können sehr strikt sein und nur ein bestimmtes Zeichen akzeptieren. Zwischen diesen beiden Extremen sind alle Nuancen denkbar.
Um derartige Dateien dennoch auch auf dem System Ihrer Wahl lesbar zu machen, gibt es zwei Möglichkeiten: Entweder verwenden wir ein Programm, dass auch exotische Typen von Zeilenumbrüchen versteht, oder wir tauschen das Zeichen für den Zeilenumbruch in diesen Dateien vor einer weiteren Ansicht oder Bearbeitung aus. Wie das funktioniert, schauen wir uns im nächsten Abschnitt an.
Änderung des Zeilenumbruchtyps von Dateien
Wenn Sie Textdateien von anderen Betriebsystemen oder sonstigen Quellen, die einen von Ihrem Betriebssystem abweichenden Zeilenumbruchtyp verwenden, auch auf Ihrem System nativ lesen möchten, können Sie die Zeilenumbrüche der betreffenden Dateien umschreiben beziehungsweise die alten Zeilenumbrüche gegen den von Ihnen präferierten Zeilenumbruchtyp austauschen. Solch eine Umschreibung kann darüber hinaus auch erforderlich sein, wenn Sie Ihre Textdateien mit einem Programm einlesen möchten, das nur eine bestimmte Art von Zeilenumbruchtyp versteht und selber keine Konvertierungen vornehmen kann.
Zeilenumbruchtyp mit dem TextEncoder ändern
Unabhängig davon, wofür Sie den Zeilenumbruchtyp von Dateien ändern möchten, können Sie diese Änderung komfortabel und sogar mit einer beliebigen Anzahl von Dateien gleichzeitig, mit der Software TextEncoder vornehmen. Folgen Sie dazu einfach den folgenden Schritten:
- Ziehen Sie zunächst alle Dateien, dessen Zeilenumbruchtyp Sie ändern möchten, auf den Text Encoder. Alternativ können Sie die Dateien auch einzeln öffnen oder ganze Ordner mit beliebigen Filtern nach Dateien durchsuchen.
- Auf der rechten Seite des Hauptfensters unter "Änderungen" > "Zeilenumbrüche" wählen Sie unter "Speichern als" Ihren gewünschten Ziel-Zeilenumbruch aus, zum Beispiel "CRLF - Windows" oder "LF - Unix".
- Optional: Unter "Einlesen als" können Sie optional angeben, welche Art von Zeilenumbruchtyp für das Lesen der Dateien verwendet werden soll. Standardmäßig wird die Option "Automatische Erkennung" verwendet, die für die meisten Fälle ausreichend sein sollte. Bei exotischeren Zeilenumbruchtypen wie zum Beispiel Zeilenumbrüchen, die durch eine fixe Zeilenlänge definiert sind, oder Zeilenumbrüche, die auf benutzerdefinierten Codepoints basieren, sollten Sie hier aber eine entsprechende Auswahl treffen.
- Rechts unten im Hauptfenster finden Sie die Speicheroptionen. Hier bestimmen Sie, ob Sie die jeweilige Originaldatei überschreiben möchten oder Sie die konvertierten Dateien als neue Dateien zum Beispiel in einem neuen Ordner ablegen möchten.
- Zuletzt klicken Sie auf den Button "Konvertieren und Speichern" unter den Speicheroptionen. Damit wird der Zeilenumbruch aller Dateien, die sich aktuell in der Dateiliste des Programms befinden, gemäß Ihren aktuellen Einstellungen geändert.
Der TextEncoder unterstützt sowohl für das Einlesen als auch für das Speichern der Textdateien alle in diesem Tutorial vorgestellten zeichenbasierten Zeilenumbruchtypen sowie Zeilenumbrüche nach einer festen Anzahl von Zeichen. Darüber hinaus können auch benutzerdefinierte Zeilenumbrüche über einzelne oder mehrere Zeichen oder Codepoints definiert und in der Anwendung verwendet werden.
Wenn Sie die Änderung des Zeilenumbruchs einzelner oder mehrerer Dateien (zum Beispiel aller Dateien aus einem spezifizierten Ordner) über ein Skript automatisieren möchten, können Sie dafür den TextEncoder in der Version TextEncoder Pro CL verwenden.
Zeilenumbruchtyp mit dem TextKonverter ändern
Auch mit dem Programm Text Konverter ist es möglich, die verwendeten Zeilenumbrüche von Textdateien zu ändern. Die Vorgehensweise ist die gleiche, wie sie soeben für den TextEncoder beschrieben wurde. Auch die Auswahl unterstützter Zeilenumbruchtypen ist zum TextEncoder identisch.
Jedoch befinden sich die Zeilenumbruch-Optionen beim TextKonverter nicht unter "Änderungen > Zeilenumbrüche" sondern unter "Aktionen > Dateien > Zeilenumbruchtyp". Darüber hinaus können Sie den TextKonverter auch für zahlreiche andere Bearbeitungen von Text-, CSV-, und XML-Dateien verwenden, während der TextEncoder nur dafür gedacht ist, die Kodierung sowie den Zeilenumbruchtyp von Textdateien zu ändern. Auch den Text Konverter gibt es als Batch Version, die sich über die Kommandozeile oder per Skript steuern und automatisieren lässt.
Dateien mit gemischten Zeilenumbrüchen
Im Abschnitt "Erkennung des Zeilenumbruchtyps einer Datei" hatten wir bereits den Fall angesprochen, dass es Textdateien geben kann, die mehrere Arten von Zeilenumbrüchen gleichzeitig enthalten können. Einer solche Datei kann dann keiner der möglichen Zeilenumbruchtypen eindeutig zugeordnet werden.
Entstehung von Dateien mit gemischten Zeilenumbrüchen
Entstehen können derartige Dateien mit gemischten Zeilenumbrüchen auf verschiedene Weise:
Möglich ist zum Beispiel, dass eine Datei von möglicherweise unterschiedlichen Personen auf verschiedenen Systemen bearbeitet wurde. Falls diese Personen beispielsweise einen Texteditor verwendet haben, der nur den eigenen System-Zeilenumbruchtyp verstehen und schreiben kann, ist folgendes schnell passiert: Person A erstellt eine Textdatei auf Linux. Die resultierende Datei enthält zu diesem Zeitpunkt ausschließlich den Unix-Zeilenumbruchtyp LF. Anschließend öffnet Person B die Datei unter Windows und beginnt einige Absätze hinzuzufügen. Diese neuen Absätze werden unter Verwendung des Windows-Zeilenumbruchs CR LF in die Datei hinein geschrieben, die alten LF-Zeilenumbrüche bleiben dagegen unangetastet. Schon trägt eine solche Datei ungewollt mehrere Arten von Zeilenumbrüchen in sich.
Dasselbe kann passieren, wenn mehrere Dateien unterschiedlicher Systeme aneinandergehängt werden, ohne vorher den Zeilenumbruchtyp der Dateien aufeinander abzustimmen.
Reparatur von Dateien mit gemischten Zeilenumbrüchen
Was können wir aber tun, wenn es schon zu spät ist? Wie können wir eine solche Datei mit gemischten Zeilenumbrüchen wieder reparieren? Zum Glück müssen wir uns darum nicht händisch kümmern, sondern können wieder zum TextEncoder greifen, der bereits im letzten Abschnitt vorgestellt wurde. Wie dies genau funktioniert, ist im Tutorial "Textdateien mit gemischten Zeilenumbrüchen reparieren" erklärt.
Und damit es beim nächsten Mal nicht wieder zu Dateien mit gemischten Zeilenumbrüchen kommt: Mehrere Text-Dateien unter Berücksichtigung ihrer verschiedenen Zeilenumbruchtypen aneinander zu hängen beherrscht das Programm TextKonverter. Und das natürlich ohne dass Sie sich explizit darum kümmern müssen.