Nie ma czegoś takiego, jak czysty tekst. Awantura o koniec linii

Opisywany niedawno standard UTF-8 okazał się być karkołomnym, ale bardzo skutecznym rozwiązaniem problemu stron kodowych i jako jedyne podejście wielobajtowe nie wywołał więcej szkody niż pożytku. Na szczęście z biegiem lat stał się de facto internetowym standardem w poczcie i stronach WWW. Choć jeszcze dekadę temu zdarzało się znaleźć witryny zakodowane w ISO-8859-2, dziś nawet polskie strony stosują UTF-8.

Awantura o koniec linii (fot. Pixabay)
Awantura o koniec linii (fot. Pixabay)
Kamil J. Dudek

28.03.2020 23:19

Wydawałoby się zatem, że kodowanie znaków to jedno z tych zagadnień, które po wieloletnich wojnach inżynieryjnych zostało wreszcie rozwiązane, pozostawiając wyłącznie kwestię "legacy", danych stworzonych w czasach bez ujednoliconego standardu, na starych systemach. Wymiana "obecnych" danych nie powinna już nastręczać trudności, bo międzynarodowy charakter przetwarzania danych wręcz wymusił zgodność z UTF-8.

Postęp i elektryfikacja

Życie uczy jednak, że da się pokłócić o wszystko, a mnogość opinii (i w konsekwencji mnogość implementacji) jest nieunikniona. Zachowanie zgodności z ASCII wywołało wprowadzenie zgodności z bardzo, bardzo dawnymi standardami telegraficznymi, teleksami oraz elektrycznymi maszynami do pisania. Otworzyło to wrota piekieł w kwestii tak trywialnej, jak... koniec linii.

Początkowo elektroniczne przetwarzanie tekstu wiązało się jednoznacznie z zamiarem docelowego wydrukowania go. Ponieważ papier nie ma nieskończonej szerokości, a automatyczne łamanie linii jest niejednoznaczne i wymaga przetwarzania, wprowadzono znaki pozwalające przejść wiersz niżej.

Białe znaki włączone: bajty CR i LF widoczne na końcach linii
Białe znaki włączone: bajty CR i LF widoczne na końcach linii

Technicznie, proces "pisania pod spodem" w przypadku automatycznych dalekopisów polega na podniesieniu kartki o jeden wiersz w górę, a następnie przesunięciu pisaka z powrotem na początek papieru. Są to więc dwie czynności, wskutek czego obsługują je dwa sygnały: podanie linii (line feed, LF) oraz powrót pisaka (carriage return, CR). Oba sygnały mają swoje miejsce w tablicy ASCII i wszystkie stosowane kodowania znaków rozumieją zarówno CR, jak i LF.

Wiele rozwiązań prostego problemu

Problemem jest implementacja. Twórcy systemu Unix stwierdzili, że nie każdy plik tekstowy musi od razu iść na drukarkę i wystarczy tylko jedna informacja o tym, że gdzieś kończy się linia. Dlatego pliki stworzone na systemach uniksowych stosują jedynie bajt LF. Klasyczny system Mac OS również twierdzi, że do oznaczania nowej linii wystarczy jeden bajt, ale wybrano do tego celu bajt CR. MS-DOS i klasyczny Windows, a także OS/2 i Windows NT stosują standard ANSI, co zapewne było konsekwencją tworzenia systemu PC DOS pod egidą firmy IBM.

Niepołamane linie i dziwne "^M" na początku: plik z Windows na Linuksie
Niepołamane linie i dziwne "^M" na początku: plik z Windows na Linuksie

Efekty owej rozbieżności prowadzą do tego, że uniksowe pliki tekstowe w systemie Windows wyglądają jak jedna długa linia (i tak też są parsowane na niższych poziomach). Nowsze wersje Windows dokonują w wielu miejscach korekty wizualnej: edytor ISE PowerShella, WordPad, a w późniejszych wydaniach Windows 10 również i Notatnik potrafią wyświetlać pliki z samym LF z poprawnie połamanymi liniami. Skrypty PowerShella z samym LF działają poprawnie (!), ale skryptu CMD już nie.

Obraz

Gorzej sprawa ma się w drugim kierunku: systemy uniksowe widzą pliki z CR+LF jako tekst ze śmieciowym bajtem na końcu każdej linii. Może to wywoływać problemy podczas parsowania. Skrypty powłoki z takimi śmieciami nie będą poprawnie działać, kod C nie będzie się budować. Wystarczy raz zagapić się i zapisać plik w złym edytorze. Podobną krzywdę można sobie zrobić ze spacjami i tabulacjami w Pythonie... Wiele uniksopododnych systemów zawiera narzędzie pozwalające szybko rozwiązać kłopot śmieciowych CR na końcach linii. Jest nim dos2unix.

Wieczyste niedopatrzenia

Problemu nie da się oczywiście rozwiązać wprowadzeniem symbolu "koniec linii, ale tym razem na serio", bo jest na to za późno. Jest on także czymś innym niż problem ze stronami kodowymi, łatwo zatem o plik w którym równolegle egzystują problemy z łamaniem linii oraz niejasne kodowanie.

Z punktu widzenia systemu, dane to dane. Dopiero bardzo koślawe kodowanie, jak UTF-16, sypiące NULL-ami w środku pliku, może sprawić że jego przetwarzanie skończy się awarią. Znak końca linii sprawia jednak problemy na nieco wyższej warstwie, na przykład powłoce.

Problem końca linii prawdopodobnie pozostanie z nami już na zawsze. Przejście do nowej linii nie jest bowiem ani "powrotem karetki" ani "wysunięciem papieru". Każde podejście jest próbą ujarzmienia przeterminowanych konceptów, więc nie istnieje w takim układzie dobre rozwiązanie.

Programy

Zobacz więcej
Wybrane dla Ciebie
Komentarze (74)