.pl .en .de .ru
Interdyscyplinarny blog badawczy pracowników Instytutu Językoznawstwa i Pracowni Systemów Informacyjnych UAM

Anatomia pliku tekstowego — część IIb (piekło końca wiersza, cd.)

Filip Graliński
03/04

Piekło końca wiersza ma zakątki, o których dowiedziałem się dopiero niedawno…

Jak wiemy z poprzedniego wpisu z tego cyklu w różnych systemach operacyjnych różnie zaznacza się koniec wiersza — w Linuksie używamy znaku o kodzie (szesnastkowo) 0a, w Windowsie — dwuznaku 0d-0a. A co jeśli użyjemy samego znaku o kodzie 0d (w wielu językach programowania oznaczanego za pomocą sekwencji \r)??

Spreparowałem przykładowy plik tekstowy zawierający taki izolowany znak (do pobrania tutaj) — plik zaczyna się tekstem „Ala ma kota”, po którym następuje znak o kodzie 0d, dalej tekst „Basia ma psa” i na końcu zwykły znak końca wiersza. (Plik trzeba najpierw rozpakować — pamiętajmy, by nie zamieszczać w Internecie i nie załączać w mejlach „gołych” plików tekstowych!) Czyli plik w środku wygląda tak:

$ hexdump -C ukryte.txt
00000000  41 6c 61 20 6d 61 20 6b  6f 74 61 0d 42 61 73 69  |Ala ma kota.Basi|
00000010  61 20 6d 61 20 70 73 61  0a                       |a ma psa.|
00000019

Jak taki plik jest widziany w systemie Linux? Polecenie wc (do zliczania wierszy, wyrazów i znaków) nie przynosi niespodzianki:

$ wc ukryte.txt
1  6 25 ukryte.txt

Wszystko się zgadza — w końcu plik ma jeden wiersz.

Także polecenie grep (do przeszukiwania plików tekstowych) potwierdza, że w środku jest wiersz z napisem np. „Ala”:

$ grep 'Ala' ukryte.txt
Basia ma psa

Ejże, wiersz został wypisany, ale gdzie jest „Ala ma kota“?!?

Hmmm, wyrzućmy po prostu zawartość pliku na konsolę za pomocą polecenia cat:

$ cat ukryte.txt
Basia ma psa

Arrgh, co się stało z tą Alą??

Sprawdźmy używając czegoś troszkę bardziej zaawansowanego niż polecenia cat — przeglądarki plików tekstowych less:

$ less ukryte.txt
Ala ma kota^MBasia ma psa
ukryte.txt (END)

(Z programu less wychodzimy, naciskając przycisk „q”, jakby kto nie wiedział).

Ha, a więc „Ala” przed lessem się nie schowała! O co tutaj chodzi?

Dobrze, oto wyjaśnienie: znak 0d to znak powrotu karetki, czyli instrukcja (np. dla drukarki), by powrócić na początek wiersza (ale nie schodzić niżej). Polecenie cat posłusznie wykonuje to polecenie (po czym nadpisuje „Alę” „Basią”), natomiast less pokazuje nam znak 0d za pomocą sekwencji „^M”.

Widzę tu duży potencjał dla psikusów kosztem linuksowców…

kto częściej używa znaku powrotu karetki — kobiety czy mężczyźni?

Skąd o tym się dowiedziałem? Otóż na ćwiczenia z „Inteligentnych systemów informacyjnych” poprosiłem studentów, aby zmierzyli się z wyzwaniem „rozpoznaj płeć”. Wkrótce niektórzy ze studentów zaczęli narzekać, że nie zgadza się długość pliku wejściowego. Zacząłęm sprawdzać za pomocą poleceń wc, grep i cat i, jak można się domyślać, wszyscyśmy popadli w konfuzję… dopóki nie użyłem programu less.

No cóż, okazało się, że nie przeczyściłem korpusu „płci” ze znaków powrotu karetki. OK, mea culpa, ale z drugiej strony, znak o kodzie 0d nie jest przecież znakiem końca wiersza (jakiegokolwiek systemu operacyjnego byśmy nie użyli).

Zaraz, a skąd się wzięła ta pozornie nieprawidłowa liczba wierszy?

a w Windowsie…

… otóż okazuje się, że Windowsie znak powrotu karetki jest jednak (przynajmniej czasami) traktowany jako znak końca wiersza! Konkretnie czyni to interpeter języka Python. Napiszmy prosty program w Pythonie do zliczania wierszy pliku tekstowego:

import sys

line_count = 0

for line in sys.stdin:
   line_count += 1

print(line_count)

W Linuksie taki program dla naszego przykładowego pliku wypisuje na ekranie „1” (i dobrze) — bez względu na to, czy używamy Pythona w wersji 2 czy 3. Jeśli jednak ten pythonowy skrypt uruchomimy w Windowsie, Python 2 wypisze „1”, natomiast Python 3 — „2”. Brrr… co za nonsens!

Tagi