= Jak vytvořit korpus = #Jak_vytvo.2BAVk-it_korpus [[BR]] Tento článek slouží jako průvodce při vytváření korpusu. Je určen pro studenty a další zájemce, kteří chtějí pořizovat a převádět data pro potřeby korpusů. Za prvé popisuje strukturu korpusů, s využitím odkazů na příslušné normy. Za druhé popisuje možnosti kontroly správnosti korpusových dat. A za třetí podává návod, jak vytvářet korpusy převodem z HTML stránek. == Úvod == #A.2BANo-vod === Co jsou to korpusy === #Co_jsou_to_korpusy Obecně - počítačový korpus je rozsáhlý, vnitřně strukturovaný a ucelený soubor textů daného jazyka, elektronicky uložený a zpracovávaný. Práci s korpusovými daty zprostředkovává program nazývaný korpusový manažer. Aby mohl být určitý text do korpusu zařazen, musí být připravena dvojice textových souborů - tzv. vertikální text (zkráceně vertikál) a metainformace. Vertikál obsahuje samotná korpusová data, metainformace obsahují doplňující údaje o těchto datech. V tomto textu bude množina takových dvojic souborů označována zjednodušeně jako korpus (viz dále). == Struktura korpusových dat == #Struktura_korpusov.2BAP0-ch_dat === Jak jsou korpusy uloženy === #Jak_jsou_korpusy_ulo.2BAX4-eny Korpusy jsou uloženy jako textové soubory. Korpus je jednoznačně určen jménem adresáře. Všechny soubory, které končí .vert (vertikály) a .meta (metainformace) a které jsou obsaženy v tomto adresáři a všech jeho podadresářích, tvoří korpus. === Struktura vertikálů === #Struktura_vertik.2BAOE-l.2BAW8- Strukturu vertikálů popisuje norma pro vertikály [[PopisVertikalu| Popis vertikálů]] . === Struktura metainformací === #Struktura_metainformac.2BAO0- Strukturu metainformací popisuje norma pro metainformace [[PopisMetainformaci| Popis metainformací]] . === Vazby mezi vertikály a metainformacemi === #Vazby_mezi_vertik.2BAOE-ly_a_metainformacemi 1. V každém adresáři či podadresáři si musejí co do počtu i do jmen (až na příponu) tyto odpovídat. 1. Každý z dvojice (vertikál, metainformace) obsahuje dokumenty stejných jmen ve stejném pořadí. Příklad: * mf-1999-05-17.vert obsahuje dokumenty "" až "" * mf-1999-05-17.meta obsahuje dokumenty "Doc : mf/1999/05/17/1" až "Doc : mf/1999/05/17/159" == Nástroje pro kontrolu správnosti korpusových dat == #N.2BAOE-stroje_pro_kontrolu_spr.2BAOE-vnosti_korpusov.2BAP0-ch_dat Dají se rozdělit na tři skupiny: * kontrola konzistence mezi vertikály a metainformacemi * kontrola vertikálů * kontrola metainformací Všechny jsou dostupné po přidání modulu: {{{ $ module add corpus }}} na strojích aurora (Linux), aisa (IRIX) a oreias (SunOS). === Pomocné programy === #Pomocn.2BAOk_programy Většina programů pracuje se standardním vstupem a výstupem. To znamená, že kontrolní program nezná jméno souboru, jehož obsah mu byl přesměrován na jeho standardní vstup. Proto je tu program `check_file`. Použití: {{{ check_file [-l číslo -s -S] program file $ check_file -l 20 meta_check neco.meta }}} Jako argumenty mu dáme jméno kontrolního programu a souboru, který chceme zkontrolovat. Jeho výstup obsahuje jméno kontrolovaného souboru a výstup kontrolního programu. Volby: * -l číslo ... výstup kontrolního programu se ořeže na 'číslo' řádek * -s ... totéž co -l 0 * -S ... pokud kontrola byla bez chyby, potlačí všechen výstup Další pomocný program je `traverse_dir`, který je vystavěn na programu ` find `. Použití: {{{ traverse_dir [-v] suffix program [argumenty pro program] $ traverse_dir vert check_file -S xml_check }}} Suffix je buď `vert` nebo `meta`. Program vyhledá všechny soubory s příponou suffix a provede volání specifikovaného programu s jeho argumenty a jako poslední argument přidá jméno nalezeného souboru. Takže v ukázkovém případu se volá ` check_file -S xml_check neco.vert`. Volba `-v` provede navíc výpis těchto volání. === Kontrola konzistence mezi vertikály a metainformacemi === #Kontrola_konzistence_mezi_vertik.2BAOE-ly_a_metainformacemi Kontroluje se, jestli si odpovídají soubory .vert a .meta: {{{ $ v2m_files }}} Dále se kontrolují seznamy jmen dokumentů - program `v2m_docs`. Kontrola jedné dvojice souborů .meta a .vert: {{{ $ v2m_docs soubor.meta #Zadám jen jméno metainformací }}} Kontrola celého korpusu: {{{ $ traverse_dir meta v2m_docs }}} === Kontrola vertikálů a metainformací === #Kontrola_vertik.2BAOE-l.2BAW8_a_metainformac.2BAO0- K dispozici jsou tyto programy: 1. `il2_check` [[BR]] Určeno pro: *.vert, *.meta. Kontroluje kódování češtiny. Ohlásí podezřelé znaky. Je nutno zvážit, zda se jedná o skutečnou chybu nebo ne. 1. `tags_check` [[BR]] Určeno pro: *.vert. Kontroluje, zda řádky, které vypadají jako značky, jsou ze seznamu povolených značek. 1. `pozice_check` [[BR]] Určeno pro: *.vert. Kontroluje, zda řádky, které nejsou značkami, jsou dále nedělitelné pomocí funkce Corpus::split(). 1. `heuristic_check` [[BR]] Určeno pro: *.vert. Kontrola pozic, zda neobsahují řídící a značkovací řetězce originálního textu. Hledá HTML značky a příkazy LATEXu. 1. `xml_check` [[BR]] Určeno pro: *.vert. Kontrola struktury vertikálů. 1. `meta_check` [[BR]] Určeno pro: *.meta. Kontrola struktury metainformací. Všechny tyto programy jsou filtry. Proto je používáme jedním z těchto tří způsobů: {{{ $ xml_check < soubor.vert > zde_je_vystup 2>&1 }}} nebo: {{{ $ check_file xml_check soubor.vert > zde_je_vystup }}} nebo: {{{ $ cd adresar_s_daty $ traverse_dir vert check_file xml_check > zde_je_vystup }}} Všechny kontroly se dají spustit pomocí dávky `check_all`: {{{ $ check_all > zde_je_vystup 2>&1 }}} === Jak číst výstupy kontrolních programů === #Jak_.2BAQ0A7Q-st_v.2BAP0-stupy_kontroln.2BAO0-ch_program.2BAW8- * `v2m_files, v2m_docs`[[BR]] Oba programy používají při hlášení rozdílů v seznamech jmen (`v2m_files` - jmen souborů a `v2m_docs` - jmen dokumentů) standardní program `comm` s parametrem `-3`. Ten uvede rozdíly ve dvou tabulátorem odsazených sloupcích. Viz také `man comm`. * `il2_check, tags_check, pozice_check, heuristic_check, meta_check` [[BR]] Tyto programy mají snadno čitelný výstup, a není tedy nutno jej zde dále komentovat. * `xml_check` [[BR]] Program `xml_check` je založen na volání xml-parseru `rxp`. Jen je proveden určitý preprocessing - viz kapitola [[PopisVertikalu#rozdily| Rozdíly mezi vertikálem a jeho DTD definicí]] Výstup programu bude vyložen na několika příkladech: {{{ VSTUP č.1: VÝSTUP: Warning: Content model for vertical does not allow it to end here in unnamed entity at line 4 char 11 of VYSVĚTLENÍ: Vertikál neobsahoval žádný dokument, ale párová značka nesmí být prázdná. ---------- VSTUP č.2: (jen jeho relevantní část) Ahoj Jaroslav VÝSTUP: Warning: Content model for doc does not allow element z here in unnamed entity at line 5 char 3 of VYSVĚTLENÍ: Po značce musí bezprostředně následovat npaříklad nebo

a nikoli pozice (element z označuje pozici Ahoj). --------- VSTUP č.3: (jen jeho relevantní část)

V zázemí blabla

VÝSTUP: Content model for p does not allow element head here in unnamed entity at line 6 char 6 of VYSVĚTLENÍ: V

nesmí být zanořen --------- VSTUP č.4: (jen jeho relevantní část)

V

A VÝSTUP: Warning: Content model for p does not allow element p here in unnamed entity at line 7 char 3 of Error: Mismatched end tag: expected

, got
in unnamed entity at line 9 char 6 of VYSVĚTLENÍ: Neuzavřené značky

. --------- VSTUP č.5: (jen jeho relevantní část)

konec VÝSTUP: Warning: Content model for p does not allow element g here in unnamed entity at line 6 char 3 of VYSVĚTLENÍ: Značka zde nemůže být, protože musí být vždy z obou stran obklopena pozicemi, které spojuje a zde je nad ní nikoli pozice, ale značka

. Tato chyba nemůže vzniknout, pokud se použije na "rozsekání" textu funkce Corpus::split nebo program corus_split. }}} == Převod HTML stránek na vertikální tvar == #P.2BAVk-evod_HTML_str.2BAOE-nek_na_vertik.2BAOE-ln.2BAO0_tvar Pokud si jako zdroj zvolíme webovské HTML stránky, potom jsou zde k dispozici nástroje pro převod do vertikálu. Jsou založeny na perlovském modulu HTML::Parser (`man HTML::Parser`) a na funkci Corpus::split. HTML stránky obsahují kromě značek také ještě posloupnosti znaků zvané entity, například & nebo anebo °. Tyto entity je třeba převést na odpovídající znaky. K tomu je k dipsozici filtr nazvaný `html`. Dokumenty jsou často v jiném kódování (1250), v tom případě je třeba použít filtr `cstocs 1250 il2` a to až po aplikaci filtru ` html` (jinak by došlo k chybnému převodu entit typu °). Pomocný program `vert2xml` vznikl k překlenutí rozdílů mezi starší a novější definicí struktury vertikálu. Pracuje jako filtr, který přidá ke svému vstupu hlavičku vertikálu (první tři řádky), opraví tvar některých značek a přidá na konec řádek . Programy dále popsané dávají výstup ve starším formátu, proto jako postprocessing je vhodné zařadit filtr `vert2xml`. Vzhledem k tomu, že struktura HTML dokumentů je celkem volná, pouhým překladem značek nedospějeme ke dobře utvořenému vertikálu. Proto jsou dále popsány prográmky na úpravu některých neduhů - provádějí párování, rušení nebo vkládání značek. Několik programů je spojeno do dávky `tags_all`, kterou je možné použít jako poslední postprocessing. === Příklad 1. - nejjednodušší použití === #P.2BAVkA7Q-klad_1._-_nejjednodu.2BAWEBYQDt_pou.2BAX4-it.2BAO0- Je implementováno v programu [http://nlp.fi.muni.cz/cs/Jak_vytvorit_korpus?action=AttachFile&do=view&target=html2vert.1 html2vert.1] . Program funguje jako filtr. Použití: {{{ html < muj.html | html2vert.1 |vert2xml | tags_all > muj.vert }}} Výpis programu: {{{ BEGIN {push @INC , #Do seznamu cest modulu pridej "/usr/local/lib/perl5/site_perl/5.005", #Cestu k modulu HTML::Parser "/packages/share/corpus/lib" #Cestu k modulu Corpus }; use Corpus; #Vyzada si balik Corpus require HTML::Parser; #Vyzada si balik HTML::Parser package Muj_Parser; #Odtud zacne balik Muj_Parser #Nastavuje dedicnost @ISA=qw(HTML::Parser); sub start {} #vola se, kdyz je rozpoznana nekoncova znacka, zatim nedela nic sub end {} #vola se, kdyz je rozpoznana koncova znacka, zatim nedela nic #Tato procedura se vola vzdy, kdyz je rozpozan nejaky text sub text { my($self, $text) = @_; #do $self, $text si ulozim parametry return unless $text; #pokud $text je prazdny, vrat se my $t=(Corpus::split($text)); #do $t uloz rozdeleny text print $t unless $t =~ /^$/; #tiskni $t, pokud neni prazdny } $p = Muj_Parser->new; #Vytvorim novy objekt tridy Muj_Parser $p->parse_file(\*STDIN); #Volam parsovani standardniho vstupu }}} Program převede entity, vypustí všechny HTML značky a text "rozseká" pomocí funkce Corpus::split na pozice. Proto jediná značka ve výstupu bude .[[BR]] Program funguje takto:[[BR]] Metoda parse_file postupně zpracovává STDIN a vždy, když rozpozná nějakou značku, zavolá proceduru start, případně end, a tuto značku, převedenou na malá písmena a zbavenou atributů, předá jako druhý argument. Text mezi značkami je předán proceduře text. === Příklad 2. - přidání některých značek === #P.2BAVkA7Q-klad_2._-_p.2BAVk-id.2BAOE-n.2BAO0_n.2BARs-kter.2BAP0-ch_zna.2BAQ0-ek Je k dispozici v souboru [http://nlp.fi.muni.cz/cs/Jak_vytvorit_korpus?action=AttachFile&do=view&target=html2vert.2 html2vert.2] . Pokud budeme chtít, aby se ve výsledném vertikálu objevily značky , resp.

, tehdy, když ve zdroji byly značky , resp.

, změníme definici procedur start a end tak, aby tiskly značky, když se rozpoznají jejich HTML ekvivalenty. Navíc do značky se přidá jako atribut jméno, které je prvním argumentem programu. Použití : {{{ html < muj.html | html2vert.2 blabla | vert2xml | tags_all > muj.vert }}} Změněné procedury: {{{ sub start { my($self, $tag) = @_; if ($tag eq "html") {print "\n"}; if ($tag eq "p") {print "

\n"}; } sub end { my($self, $tag) = @_; if ($tag eq "html") {print "\n"}; } }}} === Příklad 3. - pokročilejší značení === #P.2BAVkA7Q-klad_3._-_pokro.2BAQ0-ilej.2BAWEA7Q_zna.2BAQ0-en.2BAO0- Je k dispozici v souboru [http://nlp.fi.muni.cz/cs/Jak_vytvorit_korpus?action=AttachFile&do=view&target=html2vert.3 html2vert.3] . Testovací soubor lidových novin je v souboru ln-1999-11-10.all[https://nlp.fi.muni.cz/nlp/cgi-local/edit.cgi/NlpCz/ln-1999-11-10.all ?] . Použití: {{{ html < ln-1999-11-10.all | html2vert.3 l n | vert2xml | tags_all > muj.vert }}} Předpokládejme strukturu HTML dokumentu reprezentovanou těmito zanořenými značkami (text byl vypuštěn - viz [http://nlp.fi.muni.cz/cs/Jak_vytvorit_korpus#html_pp html_pp]): {{{


}}} Toto je zjednodušená struktura HTML souborů na serveru www.trafika.cz (dnes již na [http://noviny.trafika.cz/ noviny.trafika.cz] deníky Lidové noviny, Mladá fronta Dnes a Právo nenajdete). Jeden soubor bude převeden na vertikál s několika dokumenty. Jeden dokument odpovídá kontejneru značek
a
. Proto do vertikálu pustíme jen text z těchto oblastí. Navíc víme, že text zanořený ve značkách a je tučnou kurzívou vysázené jméno autora, které chceme mít ve vertikálu mezi značkami a . Dále budeme jednotlivé dokumenty číslovat, dvanáctý dokument Lidových novin bude . Předefinujeme procedury start, end a text: {{{ sub start { my($self, $tag) = @_; if ($tag eq "div") {$self->{"poradi"}++; #zvysim si pocitadlo print "{poradi}>\n"; #tisknu $self->{"div"}=1; #indikuju oblast div } elsif ($tag eq "p") {print "

\n" if $self->{"div"}; } #tisknu

, pokud je div elsif ($tag eq "b") {$self->{"b"}=1} #indikuju b elsif ($tag eq "i") {$self->{"i"}=1; #indikuju i print "\n" if $self->{"b"}; #tisknu , pokud je b } } sub end { my($self, $tag) = @_; if ($tag eq "b") {$self->{"b"} =0} #konci b elsif ($tag eq "i") {$self->{"i"} =0; #konci i print "\n" if $self->{"b"}; #tisknu , je-li b } elsif ($tag eq "div") {$self->{"div"} =0; #konci div print "\n"; #tisknu } } sub text { my($self, $text) = @_; #do $self, $text si ulozim parametry return unless $self->{"div"}; #Pokud neni v mezich div, tak netiskni return unless $text; #pokud $text je prazdny, vrat se my $t = (Corpus::split($text)); #do $t uloz rozdeleny text print $t unless $t =~ /^$/; #tiskni $t, pokud neni prazdny } }}} Objekt $p si nese informaci, ve kterém zanoření zrovna je, a to pomocí ukazatele $self na hash. Například `$self->{"div"} =1;` signalizuje, že jsme vstoupili do div kontejneru. === Příklad č.4 - program používaný pro převod periodik z www.trafika.cz (dnes noviny.trafika.cz) === #P.2BAVkA7Q-klad_.2BAQ0.4_-_program_pou.2BAX4A7Q-van.2BAP0_pro_p.2BAVk-evod_periodik_z_www.trafika.cz_.28dnes_noviny.trafika.cz.29 Je k dispozici bez dalších komentářů v souboru [http://nlp.fi.muni.cz/nlp/files/html2corpora html2corpora] .[[BR]] === Pomocný nástroj pro analýzu struktury HTML - html_pp (pp - pretty printer) === #Pomocn.2BAP0_n.2BAOE-stroj_pro_anal.2BAP0-zu_struktury_HTML_-_html_pp_.28pp_-_pretty_printer.29 Program slouží k tomu, aby bylo snadnější nahlédnout strukturu konkrétního HTML dokumentu. Ponechá pouze značky a odsadí je podle zanoření pomocí tabulátorů. [http://nlp.fi.muni.cz/cs/Jak_vytvorit_korpus#struktura Struktura] v předchozím příkladu byla vygenerována právě pomocí html_pp. Použití: {{{ cat ln-1999-11-10.all | html_pp }}} K běhu potřebuje perlovský modul HTML::TreeBuilder. == Programy na opravu častých chyb == #Programy_na_opravu_.2BAQ0-ast.2BAP0-ch_chyb === Pro vertikály === #Pro_vertik.2BAOE-ly Všechny jsou dostupné po přidání modulu: {{{ $ module add corpus }}} na strojích aurora (Linux), aisa (IRIX) a oreias (SunOS). Jsou to: 1. tags_pair_doc [[BR]] Páruje značku . 1. tags_rm_bad_glue [[BR]] Maže značku , pokud není "obalena" pozicemi. 1. tags_rm_multi [[BR]] Maže opakující se značky (nechá jen první výskyt z posloupnosti). 1. tags_pair_item [[BR]] Páruje značku . 1. tags_rm_empty [[BR]] Maže počáteční a koncovou značku, pokud jsou bezprostředně za sebou. 1. tags_insert_p [[BR]] Vkládá značku

před pozici tam, kde by tato pozice byla zahnízděná přímo v kontejneru značky . 1. tags_pair_p [[BR]] Páruje značku

. 1. tags_all [[BR]] Dávka, která kombinuje některé výše uvedené programy. Použití: všechny programy pracují jako filtry, takže se dají přidat na konec kolony, která produkuje vertikál. Na už vygenerovaný vertikál je vhodné je spustit pomocí pomocného programu apply_filter: úprava jednoho souboru: {{{ $ apply_filter tags_all vertikal.vert }}} úprava všech vertikálů v korpusu: {{{ $ cd korpus $ traverse_dir vert apply_filter tags_all }}} === Pro metainformace === #Pro_metainformace `atrib_insert_povinne` - program, který doplní neuvedené povinné atributy a nastaví jim hodnotu Y (nezjistitelné). Je to také filtr, takže použití vypadá takto: úprava jednoho souboru: {{{ $ apply_filter atrib_insert_povinne vertikal.meta }}} úprava všech metainformací v korpusu: {{{ $ cd korpus $ traverse_dir meta apply_filter atrib_insert_povinne }}} Vložení dalších atributů zajišťují programy: 1. atrib_insert_offset [[BR]] 1. atrib_insert_size [[BR]] 1. atrib_insert_lemmat [[BR]] 1. atrib_insert_signat (běží zatím je na auroře) Všechny programy očekávají jako svůj jediný argument jméno souboru s metainformacemi. Použití: Úprava jednoho souboru: {{{ $ atrib_insert_size vertikal.meta }}} úprava všech metainformací v korpusu: {{{ $ cd korpus $ traverse_dir meta atrib_insert_size }}} == Doplňkové programy == #Dopl.2BAUg-kov.2BAOk_programy 1. vert2xml [[BR]] Program vhodný pro transformaci starého formátu vertikálů na nový. Filtr, který vkládá tyto 3 řádky před svůj vstup: {{{ }}} a tento za svůj vstup: {{{ }}} a provádí změnu u značek ,

 a .

 1. cisti_corpus [[BR]]    Najde soubory, které nekončí .vert nebo .meta (lze je potom smazat). Použití:

{{{
$ cd korpus
$ cisti_corpus                                #vypis
$ cisti_corpus | xargs rm -f                #smazani
}}}
 1. docs2meta[[BR]]    Přejmenuje .docs soubory na .meta (docs - starší, již  nepoužívaná koncovka pro metainformace). Použití:

{{{
$ cd korpus
$ docs2meta
}}}
 1. corpus_size[[BR]]    Zjistí velikost korpusu. Na výstup dá počet pozic korpusu.

{{{
$ cd korpus
$ corpus_size
}}}