Jedním z nejjednodušších elektronických dokumentů je prostý textový soubor. I když to tak nemusí na první pohled vypadat, i prosté textové soubory skrývají některé záludnosti, pokud je chceme editovat a přenášet mezi různými platformami. Jelikož jsou i webové stránky a TeXové zdrojové texty čistě textové soubory, je dobré být si těchto úskalí vědom.
Znak, který v textovém souboru signalizuje konec řádku (často označováno EOL), je na různých platformách různý, z těch nejrozšířenějších:
Znaky CR a LF mají kořeny v technologii dálnopisných terminálů:
\n
) byl interpretován jako posun papíru o řádek
vzhůru.
\r
) byl interpretován jako návrat vozíku s papírem
nebo tiskovou hlavou.
Vytvořte si v libovolném textovém editoru několikařádkový textový soubor. Ověřte, jaký znak konce řádků je použit:
$ cat plaintext.txt
prvni radek souboru
druhy radek souboru
$ hexdump -C plaintext.txt
00000000 70 72 76 6e 69 20 72 61 64 65 6b 20 73 6f 75 62 |prvni radek soub|
00000010 6f 72 75 0a 64 72 75 68 79 20 72 61 64 65 6b 20 |oru.druhy radek |
00000020 73 6f 75 62 6f 72 75 0a |souboru.|
00000028
Z výpisu nástroje hexdump je vidět, že soubor byl
pravděpodobně vytvořen na unixovém systému, protože konce řádků
jsou reprezentovány bajty s hodnotou 0a (ve výpisu
zvýrazněné).
Nabídka Start → All Programs → Altap Salamander
vybrat soubor plaintext.txt
Soubory → Zobrazit (F3)
Zobrazit → Šestnáctkově (Ctrl + H)
Následně soubor konvertujte do podoby obvyklé na ostatních platformách.
Nabídka Start → All Programs → Altap Salamander
vybrat soubor plaintext.txt
Soubory → Převést (Ctrl + K)
Vyzkoušejte si, jaké problémy může přinést použití chybného znaku konce řádku:
#!/bin/bash
echo 'Hello World!'
exit 0
$ chmod u+x skript.sh
$ ./skript.sh
bash: ./skript.sh: /bin/bash^M: chybný interpretr: Adresář nebo soubor neexistuje
Proč došlo k uvedené chybě?
TeX se k znakům konce řádku staví rozumně a CR+LF, LF i CR jsou během čtení souboru nahrazeny znakem, který se nachází v registru \endlinechar (implicitně CR). HTML je k použitému znaku konce řádku rovněž lhostejný.
Daleko větší problémy než různé znaky ukončení řádků však přináší rozdíly v kódování textu, tzn. interpretaci významu bajtů v textovém souboru.
V současné době je nejzákladnějším standardem pro kódování textu na nejrozšířenějších platformách kód ASCII. Ten však nepokrývá potřeby většiny jazyků krom angličtiny, má jen velmi omezené pokrytí speciálních znaků apod.
Tip: Pomocí ASCII escape sekvencí ve zdrojovém textu umožňuje TeX sázet i různé cizokrajné znaky. V případě nedostupnosti vhodného znaku v použitém fontu je však výsledek vytvořen složením samotatného znaku písmene (např. d) a znaku akcentu (např. ˇ). Výsledek strojové kombinace obou znaků však často nemusí dávat optimální optický výsledek v porovnání s ručně optimalizovanou kresbou znaku (nevhodné zarovnání na osu znaku, potřeba zcela odlišné kresby háčku při kombinaci s písmenem d než při kombinaci s písmenem c apod.). K tomu řešení se tedy přistupuje jen v nouzi.
Historicky se pro potřeby neanglických jazyků začala nejdříve používat různá jednobajtová kódování. Vznikly různé standardní kódové stránky, které specifikovaly, jak interpretovat který bajt v textovém souboru. Pro češtinu se mimo jiné používalo kódování
Problém je, že jednobajtové kódování má vždy k dispozici pro jeden znak právě jeden bajt. Není tedy možné v jedné kódové stránce mít více než 256 různých znaků, což je pro některé jazyky značně omezující (extrémním příkladem může být například tradiční čínština používající tisíce různých znaků).
Informace o použité kódové stránce navíc není v čistě textovém souboru nikde uvedena. Zpracovatel tedy musí vědět, která kódová stránka byla použita, jinak dojde k chybné interpretaci textu.
Tip:
Existují nástroje, které mohou zkusit kódování textu
odhadnout. Jedním z nich je např. program
enca.
Jinou možností pro detekci kódování je např.
file -bi.
Kvůli chybějící indikaci není ani možné používat více kódových stránek v jednom souboru (např. pro zakódování textu ve dvou různých jazycích, kdy každý z nich vyžaduje jiné jednobajtové kódování).
Problémy jednobajtových kódování řeší standard Unicode. Zjednodušeně si jej můžeme představit jako seznam dvojic číslo:znak, kde je každému znaku přiřazeno nějaké jednoznačné identifikační („katalogové“) číslo. Například znak š má přiděleno číslo 353, znak – (pomlčka) číslo 8211 atd.
Tip: Velmi užitečnou aplikací pro vyhledávání informací o Unicode znacích a hledání znaků samotných je webová aplikace UniView.
Povšimněte si, že počet znaků, které Unicode pokrývá, mnohonásobně převyšuje 256 možností zakódovatelných do jediného bajtu – například ona pomlčka (–) už je spolehlivě mimo tento rozsah. Musí tedy být definován i nějaký způsob, jak vysoká „katalogová“ čísla znaků uložit jako posloupnost bajtů do souboru (k zakódování čísel větších než 255 už nám nestačí jeden bajt, takové číslo musí být uloženo v několika bajtech). Existuje několik způsobů Unicode kódování:
Příklad – endianita: Mějmě (desítkově zapsaná) čísla (mezery ve všech zápisech v příkladu jsou přidány jen pro přehlednost):
Šestnácková reprezentace čísel pak je:
Binární reprezentace čísel pak je:
Little-endian posloupnost bajtů v souboru při zápisu obou čísel za sebou:
Big-endian posloupnost bajtů v souboru při zápisu obou čísel za sebou:
Příklad – kódování UTF-8: Mějme následující Unicode znak:
Tento znak má několik možných reprezentací. Jedna možná reprezentace sestává ze tří samostatných grafémů:
Binární reprezentace čísel jednotlivých grafémů je následující:
Kódování UTF-8 nám jednoznačné zadává, jak binární reprezentaci grafémů zakódovat:
Znak Ǻ tedy zakódujeme následující posloupností pěti bajtů:
Jak jsme zmínili, existuje několik reprezentací znaku Ǻ. Namísto výše uvedené trojice grafémů můžeme např. přímo použít grafém Latin Capital Letter A with Ring Above and Acute (grafém číslo 506), který zakódujeme pomocí dvou bajtů C7 BA.
Toto nám činí problémy např. tehdy, když chceme v textu najít
konkrétní slovo. Prohlížeče a editory textových dokumentů totiž
většinou pracují na úrovni grafémů, ne znaků, a jinak
reprezentované slovo nemusí najít. Abychom se tomuto problému
vyhnuli, můžeme reprezentaci znaků v dokumentu sjednotit pomocí tzv.
Unicode
normalizace implementované např. nástrojem
uconv:
$ printf '\x41\xCC\x8A\xCC\x81' | hexdump -C
00000000 41 cc 8a cc 81 |A....|
00000005
$ printf '\x41\xCC\x8A\xCC\x81' | uconv -x any-nfc | hexdump -C
00000000 c7 ba |..|
00000002
Prohlédněte si odkazované články o jednobajtových kódováních a porovnejte rozdíly mezi kódovými stránkami.
Vyzkoušejte si, jak vypadá chybná interpretace textu při chybně zvoleném kódování v programu text zpracovávajícím.
Šíleně žluťoučký kůň úpěl ďábelské ódy.
a uložte jen
v kódování Windows CP1250.
Soubor → Nový textový soubor
V pravém dolním rohu: UTF-8 → Central European (Windows 1250)
Soubor → Uložit jako → plaintext-cp1250.txt
:w ++enc=cp1250
Převeďte soubor plaintext-cp1250.txt do Unicode v kódování UTF-8.
Soubor → Otevřít soubor… → plaintext-cp1250.txt
V pravém dolním rohu: UTF-8 → Znovu otevřít s kódováním → Central European (Windows 1250)
V pravém dolním rohu: Central European (Windows 1250) → Uložit s kódováním → UTF-8
Soubor → Uložit jako → plaintext-utf8.txt
:e ++enc=cp1250
:w ++enc=utf8
iconv -f cp1250 -t utf8 --output plaintext-utf8.txt plaintext-cp1250.txt
iconv -f CP1250 -t UTF-8 < plaintext-cp1250.txt > plaintext-utf8.txt
:set fileformat=unix
:set bomb
:w ++enc=utf8
$ chmod u+x skript.sh
$ ./skript.sh
./skript.sh: řádek 1: #!/bin/bash: Adresář nebo soubor neexistuje
Hello World!
Proč došlo k uvedené chybě?