Čeština a slovenština v prostředí Fox
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