Čeština a slovenština v prostředí FoxPro

 

 

Kódování znaků

Norma ASCII (American Standard Code for Information Interchange) definuje pouze písmena anglické abecedy, číslice, interpunkční znaménka a některé speciální znaky. Její rozšíření, nazývané extended ASCII, využívá neobsazených čísel (kódů) pro znaky s diakritickými znaménky. Vývoj směroval k vytvoření a využívání dvou sad znaků. Sada LATIN2 je určena pro východoevropské země. Obsahuje znaky české, slovenské, maďarské, rumunské, polské, německé, jugoslávské a albánské abecedy a to na úkor semigrafických symbolů. Podle tvůrců je druhá sada nazývána normou Kamenických. Obsahuje pouze znaky české a slovenské abecedy. Proti LATIN2 má bohatší zastoupení semigrafických znaků. Mezi uživateli je značně rozšířena. Ani jedna sada neumožňuje přirozené (lexikální) řazení symbolů.

V prostředí FoxPro zůstávají, v této souvislosti, k řešení problémy:

a) zatřiďování a vyhledávání záznamů podle řetězcových výrazů obsahujících znaky české a slovenské abecedy

b) převod malých písmen s diakritickými znaménky na velká a naopak

c) odstranění diakritických znamének

d) převody různě kódovaných textů

e) šifrování českých a slovenských textů.

 

Obecné řešení těchto problémů je již dávno známé. V přednášce se zaměřuji na efektivní využití nástrojů, které poskytuje systém řízení báze dat FoxPro:

a) Pro vytvoření řadicích posloupností libovolného lexikálního uspořádání symbolů, automatizované řazení záznamů podle těchto posloupností a vyhledávání záznamů bez překódovaní klíčových položek (beze změny jejich obsahu, respektive bez ohledu na velká a malá písmena, ale se správným umístěním spřežek). Jde o použití příkazů a funkcí SAVE TO, RESTORE FROM, SYS(15,,), STRTRAN(), SEEK,...

b) Pro jednoznačné vytváření klíčových položek, vstupujících do operace bez předchozího definování velkých a malých písmen. Funkce UPPER() a LOWER() totiž ignorují znaky s diakritickými znaménky.

c) Pro výstup slovenských a českých textů na tiskárnách, které neumožňují tisknout znaky české a slovenské abecedy.

d) Pro sjednocení textů pořízených v různých editorech (použití různých sad kódování znaků).

e) Pro jednoduché šifrování textů z důvodu utajení jejich obsahu.

 

 

Technika kódování

V literatuře [2] je na straně C4-196 pětiřádková zmínka o využití jednoduché transformační tabulky uložené v souboru paměťových proměnných EUROPEAN.MEM. Tabulka dovoluje řadit znaky s diakritickými znaménky bez ohledu na ně. Tato zmínka byla zdrojem následujících dedukcí.

Symbolem đ nazveme nejen každé písmeno ale i každý, nepříliš složitým způsobem, zapsatelný znak. Obecně je symbolem đ každý prvek, který není ani prázdnou množinou ani uspořádanou n-ticí (pro žádné n>1). Abecedou ł rozumíme libovolnou množinu symbolů. Nepředpokládáme, že by tato množina byla konečná. Pro nás zajímavé budou pouze konečné abecedy. Přirozenou jednotkou pro uložení číselné reprezentace (kódu) jednoho symbolu je jeden BYTE (8 bitů). Tím je dán maximální počet symbolů abecedy m = 28 = 256.

Vztah mezi symbolem a jeho počítačovou reprezentací (číslem - kódem) je dán konvencí. Vztah je jednoznačný. Je popsán v [1]. Pro naše účely, vyjmenované ad a) až ad e), není nezbytně nutná znalost kódů.

Slovem s nad abecedou ł rozumíme uspořádanou n-tici symbolů z ł (pro nějaké přirozené číslo n ż 0). Z toho plyne, že ke každému slovu S existuje právě jedno přirozené číslo n ż 0 takové, že S je uspořádanou n-ticí. Toto číslo n se nazývá délkou slova S. (Slova délky 1 jsou právě symboly.) Slovům, která mají symboly lexikálně uspořádané budeme říkat řadicí posloupnosti. V řadicí posloupnosti mají význačné postavení symboly vyjadřující nulovou hodnotu (u čísel), mezeru u znaků abecedy a prázdný symbol, který označíme -. Příklad řadicí posloupnosti velkých písmen české a slovenské abecedy:

 

S1=' AÁÄBCČDĎEÉĚFGHIÍJKLĽMNOÓÔPQRŔŘSŠTŤUÚŮVWXYÝZ'

 

(Neobsahuje znak apostrof. Apostrof nepatří mezi velká písmena. Slovo obsahující apostrof zapíšeme sa = "'".) Tato posloupnost předepisuje: Symbol 'Ä' bude řazen za 'Á', před znak 'B'. Mezera bude řazena před všechny symboly slova s1, atd. Řadicí posloupnosti můžeme spojovat (komponovat). Například: Sv = S1 + Sa (s významem: apostrof bude řazen za symbol 'Z'). Ať posloupnost ASCII kódů odpovídá svým pořadím symbolům đ ˛ ł řadicí posloupnosti S. Když S = {đ1, đ2, đ3,đ4, ...,đi,  ..., đn}, pak   = {ź1, ź2, ź3, ź4,  .., źi,..,źn}. Potom pro i=1,2,..,n lze vytvořit tabulku, ve které na pozicích źi jsou umístěny ve tvaru ASCII kódů hodnoty ői, pro které platí 0<ő1<255-n, ői+1=ői+1. Tabulka má tedy obsah: őź1, őź2, őź3,őź4, ..., őźi,  ..., őźn. (Index i platí jak pro ź tak pro ő.) Kódování jednoznačné a inverzní dostaneme pouze v případě, že žádný ze symbolů se nebude opakovat. Použijeme-li opakovaný zápis symbolu, pak opakovanému symbolu připadne nadbytečný kód, kterému budeme říkat náhradní kód. Náhradních kódů využijeme pro řazení takzvaných spřežek. Spřežkou nazveme slovo, pro které platí n > 1 a má v lexikálním uspořádání symbolů svou nezávislou pozici. (Například písmeno 'ch'. Při šifrování se vytvářejí spřežky uměle, z libovolných symbolů.)

V podstatě jde o relaci mezi ascii hodnotami symbolů abecedy a jejich pozicí v tabulce. Tato relace je inverzní s výjimkou náhradních kódů a prázdného symbolu -. Výjimečnost - je dána tím, že pozice ve slově v prostředí FoxPro se číslují od jedničky a ne od nuly. Jelikož pozice 0 ve znakovém řetězci neexistuje (počítá se od jedničky), vyhradíme nezobrazitelný symbol odpovídající kódu 0, výrazu 'zatřídění bez ohledu na symbol' nebo výrazu 'ignoruj symbol'. První výraz respektuje původní pozici následujícího symbolu, druhý ne.

 

 

Algoritmus tvoření lexikální tabulky

Algoritmus je vhodné vysvětlit na příkladu tabulky třídění, nazvané '_rt'. (Vysvětlivky psané kurzívou nejsou součástí programu.)

 

*:********************************************************  

*:                                                           

*:        Program: ZKK.PRG                                  

*:         Systém: Česká a slovenská abeceda ve FoxPro      

*:         Autor : Kincl                                    

*:  Procs & Fncts: KODUJ                                    

*:          Calls: KODUJ          (procedure in ZKK.PRG)    

*:   Memory Files: _RT.MEM                                  

*:********************************************************  

    * M O D I F I K O V A T E L N É   P Ř Í K A Z Y         

    *                                                       

* jméno transformační tabulky bez úvodního znaku '_'

Tabulky  je vhodné  pojmenovat výrazně 

                 se odlišujícím způsobem.               

tab='rt'                                                

                 Své  pojmenování  tabulky  zapíšeme do 

                 uvozovek.                              

tab='_'+tab                                             

                                                         

* řetězec čísel:                                        

ci='0123456789'                                         

                 Slovo obsahující číslice musí začínat  

                 nulou.                                 

                                                         

* řetězec velkých písmen:                               

PV=' AÁÄBCČDĎEÉĚFGHIIÍJKLĽMNŇOÓÔÖPQRŘSŠTŤUÚŮÜVWXYÝZŽ'   

                 Slovo velkých písmen  musí začínat me- 

                 zerou.  Písmena  německé  abecedy jsou 

                 zařazena  kvůli  správnému zatřiďování 

                 německých   a   maďarských    příjmení 

                 Všimneme si, že I je uvedeno  dvakrát. 

                 Tím  vytvoříme rezervu pro spřežku  CH 

                 Slovo začíná symbolem mezery.          

                                                        

* řetězec  malých písmen:                               

pm=' aáäbcčdďeéěfghiiíjklľmnňoóôöpqrřsštťuúůüvwxyýzž'   

                 Slovo  malých  písmen  musíme vytvořit 

                 proto,  že jim  chceme přiřadit stejné 

                 kódy jako písmenům  velkým. Tím dosáh- 

                 neme  zatřiďování bez  ohledu na  malá 

                 a velká písmena. Při opačném požadavku 

                 by malá písmena musela být umístěna ve 

                 stejné řadicí posloupnosti jako písme- 

                 na velká.                              

                                                        

* řetězec ostatních znaků:                               

zn="'@#$%^&*()_+=;:<>?/"                                

                 Slovo vytváříme jako ukázku zatřiďová- 

                 ní jiných symbolů než písmen.          

                                                         

  počáteční hodnota kódování:                           

kod=75                                                  

                 Volba počáteční  hodnoty kódování ő1   

                 musí být > 0 ale < než 255-n           

                                                         

* jméno paměťového souboru upravit v příkazu            

*  označeném *!!!!                                      

**************************************************      

*                                                        

*       V L A S T N Í   A L G O R I T M U S             

*                                                       

*                                                       

* vytvoření prázdného řetězce:                          

&tab=REPL(CHR(0),255)                                   

                 Vygenerujeme  řetězec  prázdných znaků 

                 dlouhý  255 bytů,  jelikož hodnota ex- 

                 tended  ASCII  nemůže  být  větší  než 

                 255.   Tím   zajistíme,   že   symboly 

                 neobsažené v řídící posloupnosti budou 

                 interpretovány jako prázdné symboly.   

                                                        

* výchozí hodnoty pro transformaci symbolů spřežky:      

kcm=CHR(0)                       && "c"                 

khm=CHR(0)                       && "h"                 

knm=CHR(0)                       && náhrada "ch"        

                 Pro  každou  spřežku  nutno analogicky 

                 vytvořit  proměnné  pro  uložení znaků 

                 spřežky i její náhrady.                

                                                        

DO koduj WITH kod,PV+ci+zn                              

                 V tomto příkladě jsme vytvořili řadicí 

                 posloupnost tak, aby se číslice řadily 

                 za  písmena.  Jako  poslední  se budou 

                 umísťovat   jiné   symboly.  Procedura 

                 KODUJ - viz níže.                      

                                                         

DO koduj WITH kod,pm                                    

                 Kódy  malých  písmen  musí  být stejné 

                 jako  kódy  velkých  písmen  pouze  za 

                 požadavku ignorování rozdílů malých a  

                 velkých písmen.                        

_ch=kcm+khm                                             

                 Do proměnné _ch je vložen kód spřežky  

                 ch.                                    

                                                         

_nch=CHR(ASC(knm)-1)                                    

                 Do  proměnné _nch  je vložen  náhradní 

                 kód.                                   

?                                                        

? 'Kódy a jejich náhrady:'                              

? '----------------------'                              

?' _ch = kódy_znaků_ch = "'+_ch+'"'+;                   

'          _nch = náhrada_ch = "'+_nch+'"'               

                 Pro první informaci  je zobrazen vypo- 

                 čítaný kód spřežky  ch i jeho náhradní 

                 kód.                                   

?                                                       

? 'Obsah tabulky '+tab+ ' :'                            

? '-----------------------'                             

? &tab                                                  

                 Ze  stejných důvodů  je zobrazen obsah 

                 tabulky.                                

WAIT                                                    

*!!!!!!!!!!!     Příkaz SAVE nedovoluje použít makro.   

*                Jméno souboru nutno zadat přepsáním.   

                                                        

SAVE TO _rt ALL LIKE _*                                 

                 Uchování  tabulky a  pomocných proměn- 

                 ných v souboru typu .MEM. V našem pří- 

                 padě v souboru _RT.MEM  budou proměnné,

                 _rt, _ch, _nch.                        

                                                        

CANCEL                                                  

*                                                       

*!****************************************************  

*!  Procedure: KODUJ                                    

*!  Called by: ZKK.PRG                                  

*!****************************************************  

PROCEDURE koduj                                         

PARAMETERS poc,INDEX                                    

                 Parametr  poc určuje  počátečnou ascii 

                 hodnotu  kódování őź1.  Parametr index 

                 určuje  řadicí posloupnost  S = {đ1,   

                 đ2, đ3,đ4, ...,đi, ..., đn}.           

                                                        

PRIVATE A,B,X,p,I                                       

p=poc                                                   

                 Počáteční ascii hodnota symbolů ő1.    

I=1                                                      

                 I počítá  pozici symbolu đi v  řadicí  

                 posloupnosti S.                        

                                                        

DO WHILE I<=LEN(INDEX)                                   

                 Funkce len(index) určuje délku n řadí- 

                 cí posloupnosti S.                     

                                                        

   A=SUBSTR(INDEX,I,1)                                  

                 Extrakce symbolu đi.                   

   B=ASC(A)                                             

                 Určení ascii hodnoty źi symbolu đi.    

   X=CHR(p)                                             

                 Transformace hodnoty ői do znakového   

                 tvaru.                                 

                                                        

                                                        

   &tab=STUF(&tab,B,1,X)                                 

                 Zapsání znaku uloženého v X do tabulky 

                 na pozici źi.                          

                                                        

DO CASE                                                 

   CASE A='i'                                            

     knm=X                                              

   CASE A='c'                                           

     kcm=X                                              

   CASE A='h'                                            

     khm=X                                              

 ENDCASE                                                

                  Pamatování znaků odpovídajících v no- 

                 vém  kódování spřežce  ch a náhradního 

                 znaku.                                 

   I=I+1                                                

   p=p+1                                                 

                 ői+1=ői+1.                             

                                                        

ENDDO                                                   

RETURN

 

Použití tabulky v programu

 

Při  programování  postupujeme  analogicky  podle 

 příkladu, ve  kterém chceme pracovat  se souborem STU- 

 DENTI tak, jako by byl setříděn podle položek prijmeni 

 a jmeno.                                               

                                                         

a) Příkazem                                             

                                                        

             RESTORE FROM _rt ADDITIVE                  

                                                        

 načteme do paměti proměnné  _rt, _ch, _nch, ze souboru 

 _RT.MEM.  (Nezapomeneme  na  klauzuli  ADDITIVE, jinak 

 smažeme všechny dříve definované proměnné.             

                                                        

b) Soubor otevřeme příkazem                              

                                                        

                     USE studenti                       

                                                        

c) K souboru vytvoříme indexový soubor příkazem          

                                                        

INDEX ON STRTRAN(SYS(15,_rt,prijmeni+jmeno),_ch,_nch) TO JMN

                                                        

 Funkce SYS(15,_rt,prijmeni+jmeno) chápe  ASCII kód ře- 

 tězce  prijmeni+jmeno jako  index tabulky  _rt. Znakem 

 umístěným  v tabulce  na pozici  dané indexem  přepíše 

 výchozí znak z tohoto řetězce. Funkce STRTRAN() nahra- 

 zuje výskyt  dvojice kódů, zastupujících  spřežky "CH" 

 a "ch"  (podle _ch)  náhradním kódem  uloženým v _nch. 

 (Klíčový výraz je zdánlivě nesmyslný, ale zatřídil po- 

 ložky podle řadící posloupnosti.  K ničemu jinému není 

 zapotřebí.)                                            

                                                        

d) Příkazem                                             

                SET INDEX TO JMN                        

                                                        

 přiřadíme indexový  soubor JMN k  souboru studenti. Od 

 tohoto okamžiku  se nám ve všech  funkcích a příkazech 

 bude soubor studenti jevit  jako setříděný podle polo- 

 žek prijmeni a jmeno.                                  

                                                        

e) Například příkazem                                    

                                                        

   SEEK STRTRAN(SYS(15,_rt,prijmeni+jmeno),_ch,_nch)    

                                                        

 zajistíme vyhledávání podle indexového souboru JMN.    

 

Algoritmus tvoření převodových a šifrovacích tabulek

Algoritmus je analogický k výše uvedenému. Rozdíly ilustrujeme na příkladu tvorby tabulky převodu malých písmen na velká.

 

*:********************************************************  

*:        Program: ZPV.PRG                                   

*:********************************************************  

    *                                                       

    * jméno transformační tabulky                           

    tab='_vp'                                                

    * řetězec  malých písmen:                               

    pm=' aáäbcčdďeéěfghiíjklľmnňoóôöpqrřsštťuúůüvwxyýzž'    

                     Posloupnost  znaků,které mají  být na- 

                     hrazeny, zapsané ve  tvaru řadicí  po- 

                     sloupnosti.                            

    * řetězec velkých písmen:                               

    PV=' AÁÄBCČDĎEÉĚFGHIÍJKLĽMNŇOÓÔÖPQRŘSŠTŤUÚŮÜVWXYÝZŽ'    

                     Posloupnost  náhradních  znaků zapsaná 

                     ve  stejném pořadí  jako předchozí po- 

                     sloupnost.                             

    SET TALK OFF                                            

    I=1                                                     

    &tab=''                                                 

  DO WHILE I<256                                          

     &tab=&tab+CHR(I)                                     

     I=I+1                                                

  ENDDO                                                    

                      Vygenerujeme tabulku dlouhou  255 znaků

                      ve tvaru  řetězce, ve kterém  ascii kód

                      bude stejný jako  jeho pozice  (index).

                      Tato tabulka v podstatě zajišťuje stej-

                      ný kód na výstupu funkce  SYS(15,,) ja-

                      ko  na jejím  vstupu. ( Zachování  kódů

                      nepřeváděných znaků.)                  

     I=1                                                     

   DO WHILE I<=LEN(pm)                                     

      &tab=STUF(&tab,ASC(SUBSTR(pm,I,1)),1,SUBSTR(PV,I,1)) 

      I=I+1                                                

   ENDDO                                                   

                      Na  pozici určené  ascii kódem  i-tého 

                      znaku slova  pm zapíšeme i-tý  znak ze 

                      slova PV.                              

     SAVE TO _vp ALL LIKE _vp                                

     *: EOF: ZPV.ACT                                          

 

Šifrování provádíme kombinací algoritmů uvedených v pro- gramech ZKK a ZPV. Jako spřežky volíme libovolné kombinace. Slovo délky 3 znaků ' st' nahradíme nezobrazitelným symbolem chr(1), atd. Je dovoleno nahrazovat menší počet symbolů větším.

 

Hotové tabulky

Popsaných algoritmů bylo použito pro vytvoření nejčastěji používaných tabulek:

_IK.MEM pro vytváření indexových souborů v kódu Kamenických

 

Příklad použití:

                  RESTORE FROM _ik ADDITIVE                   

                        USE studenti                         

INDEX ON STRTRAN(SYS(15,_ik,prijmeni+jmeno),_ch,_nch) TO JMN 

                      SET INDEX TO JMN                       

        SEEK STRTRAN(SYS(15,_ik,prijmeni+jmeno),_ch,_nch)     

? sys(15,_ik,'Žilina')                                       

{Z^ZbK                                                       

? sys(15,_ik,'chalupa')                                      

OXK^ghK                                                      

? strtran(sys(15,_ik,'chalupa'),_ch,nch)                     

YK^ghK                                                       

Odstranění prázdných znaků: strtran('....',str(0),'')        

 

_IL.MEM  pro vytváření indexových souborů v kódu LATIN2

 

Příklad použití:

                  RESTORE FROM _il ADDITIVE                  

                        USE studenti                         

INDEX ON STRTRAN(SYS(15,_il,prijmeni+jmeno),_ch,_nch) TO JMN 

                       SET INDEX TO JMN                      

        SEEK STRTRAN(SYS(15,_il,prijmeni+jmeno),_ch,_nch)    

 

_KM.MEM  pro převod kódu Kamenických na malá  písmena

Příklad použití:                                             

                                       ? sys(15,_km,'ŘEŠETO')

                                         řešeto              

 

_KV.MEM  pro převod kódu Kamenických na velká písmena

Příklad použití:                                             

                                       ? sys(15,_kv,'Zábřeh')

                                         ZÁBŘEH              

 

_LM.MEM  pro převod kódu LATIN2      na malá  písmena

Příklad použití:                                             

                                       ? sys(15,_lm,'ŘEŠETO')

                                         řešeto              

 

_LV.MEM  pro převod kódu LATIN2      na velká písmena

Příklad použití:                                             

                                       ? sys(15,_lv,'Zábřeh')

                                         ZÁBŘEH               

 

_KL.MEM  pro převod kódu Kamenických na kód LATIN2

Příklad použití:                                             

                                     a= sys(15,_kl,'Zábřeh') 

 

_LK.MEM  pro převod kódu LATIN2 na kód  Kamenických

Příklad použití:                                             

                                     a= sys(15,_lk,'Zábřeh') 

 

_K_.MEM  pro odstranění diakritiky z kódu  Kamenických

Příklad použití:                                             

                                       ? sys(15,_k_,'Zábřeh')

                                         Zabreh              

 

_L_.MEM  pro odstranění diakritiky z kódu  LATIN2

Příklad použití:                                             

                                       ? sys(15,_k_,'Zábřeh')

                                         Zabreh              

 

Poznámky:

a) Nezvyklá forma pojmenování tabulek a souborů byla zvolena záměrně. Je zajištěna jednoznačnost vzhledem k systémovým proměnným.

b) Výše uvedené soubory a vzor programu pro generování tabulek si lze okopírovat na katedře 303.  

 

 

Literatura:

[1] Drózd J, Novák P: K implementaci české a slovenské abecedy na osobních počítačích; BAJT 3/1990, BAJT 5/1990

 

[2] Fox Software: FoxPro Relational Database Management System, Commands & Functions; Ohio, 1990