Zpracování textu

O čem si budeme povídat?

Zpracování textu patří mezi nejb>žn>jší programátorské činnosti. Díky tomu nám v>tšina programovacích jazyků nabízí řadu specifických nástrojů, které mají zpracování textu usnadnit. V této části se podíváme na n>které z nich a na to, jak je můžeme využít při realizaci typických programátorských úloh.

Mezi nejb>žn>jší akce při práci s textem patří:

Podíváme se, jak se uvedené úkoly řeší v jazyce Python. Poté se stručn> seznámíme s tím, jaké možnosti zpracování textu poskytují jazyky VBScript a JavaScript.

Od verze 2.3 Python při zpracování textu postupuje trošku nejednoznačn>. Příčina spočívá v tom, že starší verze jazyka Python provád>ly veškeré manipulace prostřednictvím modulu, který byl nap>chovaný funkcemi a užitečnými konstantami. Python verze 2.0 zavedl pro typ řet>zec metody, které nahrazují funkce ve zmín>ném modulu, ale konstanty byly dostupné stále jen prostřednictvím modulu. Tato situace trvala až do verze 2.3. Další vývoj sm>řuje k tomu, aby potřeba používat starý modul string byla zcela odstran>na. V tomto tématu se zam>říme výlučn> na nový, objektov> orientovaný přístup k manipulaci s řet>zci. Pokud si chcete vyzkoušet práci s původním modulem, hledejte potřebné informace v jeho dokumentaci.

Rozd>lování řet>zců

Nejdříve se budeme zabývat tím, jak můžeme řet>zec rozd>lit na části, z kterých se skládá. Při zpracování textových souborů se s takovým požadavkem setkáváme často. Obsah souboru se obvykle snažíme číst po řádcích, ale požadovaná data mohou být uložena v určitých částech řádků. Jako příklad si můžeme uvést náš záznamník s adresami. Místo tisku celé adresy bychom mohli chtít přistupovat například jen k částem adresy.

V Pythonu pro tento účel použijeme metodu split() (rozd>lit na části, rozštípnout) následujícím způsobem:

>>> retezec = 'Toto je (kratky) retezec.'
>>> print retezec.split()
['Toto', 'je', '(kratky)', 'retezec.']

Povšimn>te si, že se nám vrací seznam, který obsahuje slova z řet>zcové prom>nné retezec. Všechny mezery byly odstran>ny. Předdefinovaným odd>lovačem metody split() jsou totiž bílé znaky (tj. tabulátory, znaky přechodu na nový řádek a mezery). Zkusme to znovu, ale tentokrát si jako odd>lovač vybereme otvírací závorku:

>>> print retezec.split('(')
['Toto je ', 'kratky) retezec.']

Vidíte ten rozdíl? Seznam obsahuje tentokrát jen dva prvky a otvírací závorka na začátku 'kratky)' byla odstran>na. Důležitou vlastností metody split() je to, že odstraňuje odd>lovací znaky. V>tšinou takové chování požadujeme, ale občas bychom si přáli, aby tomu tak nebylo.

K dispozici máme i metodu join(), která přebírá seznam (nebo také jinou podobu posloupnosti) řet>zců a spojuje je dohromady. Jednou z matoucích vlastností metody join() je to, že řet>zec, jehož metodu join() voláme, je použit v roli spojovacích znaků. Následující příklad ukazuje, co mám na mysli:

>>> lst = ['Tohle', 'je', 'seznam', 'slov.']
>>> print '-+-'.join(lst)
Tohle-+-je-+-seznam-+-slov.
>>> print ' '.join(lst)
Tohle je seznam slov.

Když o tom začnete přemýšlet, dává to smysl. Ale na první pohled to vypadá divn>.

Poznámka překladatele: Na první pohled by se zdálo přirozen>jší, kdyby metoda join() byla metodou typu seznam a jako parametr by přebírala řet>zec, který se použije pro spojení prvků seznamu:

>>> lst.join('-+-')    # Tohle NEFUNGUJE!

Ale argumentem metody join() nemusí být přímo seznam řet>zců. Může to být libovolný iterovatelný objekt, tj. objekt který podporuje průchod jednotlivými řet>zcovými položkami. (Typicky to bývá kontejner, ale může to být například i generátor s omezeným počtem generovaných řet>zcových hodnot.) Pokud si to uv>domíme, nevypadá už rozhodnutí o příslušnosti metody join() k řet>zcovému typu tak nezvykle. V opačném případ> by metoda join() musela být implementována pro všechny typy kontejnerů, jejichž obsah bychom cht>li spojovat. Následující příklad uvádí převod seznamu na n-tici a na množinu a spojení jejich obsahu mezerou:

>>> lst = ['Tohle', 'je', 'seznam', 'slov.']
>>> t = tuple(lst)
>>> se = set(lst)
>>> print ' '.join(t)
Tohle je seznam slov.
>>> print ' '.join(se)
je seznam Tohle slov.

Povšimn>te si, že v případ> množiny není dodrženo pořadí, ve kterém se prvky množiny vkládaly (z množinového hlediska není pořadí položek důležité). Z prvků množiny ovšem můžeme n>jakou funkcí vytvořit uspořádanou posloupnost:

>>> print ' '.join(sorted(se))
Tohle je seznam slov.

Zdánliv> správné pořadí slov je dáno pouze náhodou, protože uvedená slova ve v>t> náhodou odpovídají svému lexikografickému pořadí. Dokažme si to na jiném příklad>:

>>> lst = ['tohle', 'je', 'neusporadany', 'salat', 'z', 'ceskych', 
...        'slov', 'bez', 'diakritickych', 'znamenek']
>>> se = set(lst)
>>> print ' '.join(se)
ceskych slov neusporadany diakritickych znamenek bez salat je z tohle
>>> print ' '.join(sorted(se))
bez ceskych diakritickych je neusporadany salat slov tohle z znamenek

Počítání slov

Nyní se znovu podívejme na program pro počítání slov, o kterém jsem se zmínil v předchozí podkapitole o funkcích. Připomeňme si, že pseudo kód vypadal takto:

def pocetSlov(s):
    seznam = split(s)  # seznam, kde prvkem je vždy slovo
    return len(seznam) # vrátíme počet prvků seznamu

for radek in soubor:
    celkem = celkem + pocetSlov(radek) # sečti počty za každý řádek
print "Soubor má %d slov." % celkem

Nyní již víme, jak lze načítat řádky souboru. Podívejme se blíže na t>lo funkce pocetSlov(). Nejdříve chceme z daného řádku vytvořit seznam slov. Stačí, když na řádek aplikujeme standardní metodu split(). Nahlédnutím do dokumentace zjistíme, že zabudovaná funkce len() vrací pro seznam počet v n>m umíst>ných prvků. V našem případ> to bude počet slov v řet>zci, což je přesn> to, co potřebujeme.

Takže konečná podoba zdrojového kódu vypadá takto:

# -*- coding: cp1250 -*-
import string
def pocetSlov(s):
    seznam = s.split() # split() je metodou řet>zcového objektu s
    return len(seznam) # vrátíme počet prvků seznamu

vstup = open('menu.txt', 'r')
celkem = 0 # vytvoříme prom>nnou a nastavíme jí počáteční hodnotu nula

for radek in vstup:
    celkem = celkem + pocetSlov(radek) # sečti počty za každý řádek
print u'Soubor má %d slov.' % celkem

vstup.close()

Tento program není tak docela správný, protože například započítá samostatn> stojící znak '&' (ampersand) jako slovo (ačkoliv si vlastn> můžete myslet, že je to správné). Program navíc zpracovává jediný soubor (menu.txt). Ale není příliš obtížné upravit jej tak, aby jméno souboru četl z příkazového řádku (argv[1]) nebo prostřednictvím raw_input(), jak jsme si ukázali v podkapitole Konverzace s uživatelem. Řešení ponechávám za domácí úkol.

Vyhledávání textu

Další b>žnou operací, na kterou se teď podíváme, je vyhledávání podřet>zce v delším řet>zci. V Pythonu pro ni op>t nalezneme podporu v podob> metody zabudovaného řet>zcového typu — tentokrát se jmenuje find(). Její základní způsob použití je velmi jednoduchý. Předáte jí vyhledávaný podřet>zec, a pokud jej Python v hlavním řet>zci najde, vrátí index prvního znaku, na kterém podřet>zec začíná. Pokud podřet>zec nalezen není, vrací se hodnota -1:

>>> retezec = 'Toto je dlouhy retezec, ve kterem se nachazi podretezec.'
>>> print retezec.find('dlouhy')
8
>>> print retezec.find('moc')
-1
>>> print retezec.find('retezec')
15

První dva příklady použití jsou přímočaré. První z nich vrací index začátku podřet>zce 'dlouhy'. Druhý příklad použití vrací hodnotu -1, protože podřet>zec 'moc' se v řet>zci nevyskytuje. U třetího příkladu použití narazíme na jeden detail — vyhledal se první výskyt zadaného podřet>zce. Ale co vlastn> můžeme d>lat v případech, kdy se hledaný vzorek vyskytuje v původním řet>zci více než jednou?

Jedna z možností spočívá v použití indexu prvního výskytu a rozseknutí původního řet>zce na dv> části. Poté můžeme hledat znovu. Takto pokračujeme až do doby, kdy se nám vrátí výsledek -1:

# -*- coding: cp1250 -*-
retezec = u"'Haf, ňaf', říká pes. Kolik 'af' je v řet>zci?"
s = retezec            # Na začátku se odkazujeme na stejný řet>zec.
pocet = 0
index = s.find('af')
while index != -1:
    pocet += 1
    s = s[index + 1:]  # Budeme pracovat s druhou částí řet>zce (slicing).
    index = s.find('af')
print u"V řet>zci \"%s\" jsme našli %d výskyty vzorku 'af'." % (retezec, pocet)   

V příkladu jsme pouze výskyty vzorku pouze počítali. Stejn> dobře bychom ale mohli nalezené indexy sbírat do seznamu, který bychom využili při dalším zpracování.

Pokud použijeme nepovinné parametry metody find(), můžeme proces urychlit. T>mito nepovinnými parametry je určení počáteční a koncové pozice v původním řet>zci:

# -*- coding: cp1250 -*-
retezec = u"'Haf, ňaf', říká pes. Kolik 'af' je v řet>zci?"
pocet = 0
index = retezec.find('af')
while index != -1:
    pocet += 1
    start = index + 1  # Připravíme nový začátek.
    index = retezec.find('af', start)
print u"V řet>zci \"%s\" jsme našli %d výskyty vzorku 'af'." % (retezec, pocet)   

U tohoto řešení nemusíme pokaždé vytvářet nový řet>zec, což může být v případ> dlouhých řet>zců časov> náročné. Pokud chceme vyhledávat výskyt podřet>zce jen v n>kolika prvních znacích (a další případné výskyty nás nezajímají), můžeme určit počáteční a koncové pozice prohledávané části řet>zce takto:

# -*- coding: cp1250 -*-
retezec = u"'Haf, ňaf', říká pes. Kolik 'af' je v řet>zci?"
print retezec.find('af', 0, 20)

V souvislosti s vyhledáváním Python nabízí navíc n>kolik p>kných, speciálních metod, které se nám hodí v nejčast>jších případech — jde zejména o metody startswith() a endswith() (dalo by se přeložit jako začíná tímhle a končí tímhle). Samotná jména napovídají, so metody asi d>lají. Vracejí hodnoty True nebo False v závislosti na to, zda původní řet>zec (tj. objekt jehož metodu voláme) začíná nebo končí vyhledávaným podřet>zcem. Příklad:

>>> print 'Python jede!'.startswith('Perl')
False
>>> print 'Python jede!'.startswith('Python')
True
>>> print 'Python jede!'.endswith('je nanic!')
False
>>> print 'Python jede!'.endswith('de!')
True

Povšimn>te si, že výsledek je boolovského typu. Povšimn>te si také, že vyhledávací řet>zec nemusí mít podobu celého slova, stačí prost> podřet>zec. Pokud chcete testovat na výskyt podřet>zce jen v učité části řet>zce, můžeme upřesnit počáteční a koncovou pozici části, která se má prohledávat — stejn> jako u metody find(). V praxi se ale tenhle rys moc nepoužívá.

Na záv>r si uveďme, že pro prosté otestování, zda se podřet>zec nachází kdekoliv v řet>zci můžeme použít pythonovský operátor in takto:

>>> if 'foo' in 'foobar': print 'True'
True
>>> if 'baz' in 'foobar': print 'True'
>>> if 'bar' in 'foobar': print 'True'
True

Poznámka překladatele: Podle mého názoru uvedený příklad zbytečn> kombinuje přímo nesouvisející v>ci a svádí tak začátečníky na scestí.

  1. Pro demonstraci není vůbec nutné používat konstrukci if.
  2. Tisknout True, pokud je výsledek výrazu True navozuje představu, že jinak to není možné ukázat.

Za didaktičt>jší pokládám přímé zobrazení výsledku výrazu:

>>> print 'foo' in 'foobar'
True
>>> print 'baz' in 'foobar'
False
>>> print 'bar' in 'foobar'
True

Liší se to sice tím, že se v druhém případ> tiskne False, zatímco v původním příkladu se netiskne nic, ale asi to není na závadu. V interaktivním režimu můžeme dokonce vynechat příkaz print:

>>> 'foo' in 'foobar'
True
>>> 'baz' in 'foobar'
False
>>> 'bar' in 'foobar'
True

K vyhledávání je to zatím vše. Teď se podívejme, jak můžeme provád>t náhrady textu.

Náhrada textu

Když nalezneme hledaný podřet>zec, často jej chceme zm>nit na n>co jiného. Řešení se nám nabízí v podob> metody replace(), kterou nalezneme mezi metodami pro pythonovský typ řet>zec. Vyžaduje zadání dvou argumentů: vyhledávaný podřet>zec a řet>zec, kterým bude nahrazen. Metoda vrací nový řet>zec, který je výsledkem náhrady.

>>> retezec = 'Jedna, dv> / Honza jde / nese pytel s brouky'
>>> print retezec.replace('s brouky', 'mouky')
Jedna, dv> / Honza jde / nese pytel mouky

Zajímavé je, že metoda replace() standardn> nahrazuje všechny výskyty vyhledaného řet>zce a ne jen první výskyt, narozdíl od metody find(). (Není to zase tak překvapující, pokud si uv>domíme, že find() by při vyhledávání všech výskytů musela vracet seznam pozic. Bráno z opačného konce, u metody replace() — pokud by nahrazovala standardn> jen první výskyt — bychom zase n>jakým způsobem museli um>t předepsat náhradu všech výskytů.) Maximální počet náhrad můžeme omezit zadáním nepovinného argumentu count (tj. počet):

>>> retezec = 'Haf, ňaf, blaf, řekl pejsek.'
>>> print retezec.replace('af', 'afiky')
Hafiky, ňafiky, blafiky, řekl pejsek.
>>> print retezec.replace('af', 'afiky', 1) # jen první výskyt
Hafiky, ňaf, blaf, řekl pejsek.

Mnohem důmysln>jší operace vyhledávání a náhrad můžeme provád>t pomocí nástroje zvaného regulární výrazy. Ale práce regulárními výrazy je mnohem složit>jší, a proto si zaslouží vlastní téma v části Témata pro pokročilé.

Zm>na velikosti písmen

Poslední v>c, kterou se v této části budeme zabývat, je zm>na malých písmen na velá a naopak. Není to tak úpln> b>žná operace, ale Python nám pro tento účel nabízí pár metod:

>>> print u'SMÍšenÝ PŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ'.lower()
smíšený případ: >ščřžýáíéúůó >ščřžýáíéúů
>>> print u'SMÍšenÝ PŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ'.upper()
SMÍŠENÝ PŘÍPAD: ĚŠČŘŽÝÁÍÉÚŮÓ ĚŠČŘŽÝÁÍÉÚŮ
>>> print u'SMÍšenÝ PŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ'.swapcase()
smíŠENý přÍPAD: ĚŠČŘŽÝÁÍÉÚŮÓ >ščřžýáíéúů
>>> print u'SMÍšenÝ PŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ'.capitalize()
Smíšený případ: >ščřžýáíéúůó >ščřžýáíéúů
>>> print u'TEST'.isupper()
True
>>> print u'TEST'.islower()
False

Povšimn>te si, že metoda capitalize() (z anglického capital letter, čili velké písmeno) provádí zv>tšení prvního písmene pro řet>zec jako celek, nikoliv pro každé slovo zvlášť. Všimn>te si také dvou funcí pro otestování řet>zce na určitou vlastnost (neboli predikátů). K dalším užitečným testům patří isalpha() a isspace(). Poslední zmín>ná funkce kontroluje, zda se v řet>zci vyskytují jen bílé znaky, tedy nejen mezery (tj. také tabulátory, konce řádků...).

V dalších částech kurzu budeme mnohé z uvedených řet>zcových metod používat. Zejména Případová studie gramatického počítadla jich používá n>kolik najednou.

Poznámka překladatele: Povšimn>te si, že ve výše uvedené ukázce řet>zcových metod jsou všechny literály (řet>zcové konstanty) zapsány jako Unicode řet>zce — na začátku, před prvním apostrofem mají uvedeno písmeno u. V originálním anglickém textu tomu tak není. Ale čeština používá znaky, které nepatří do kódu ASCII, a proto význam kódu znaku závisí na tom, jaké kódování používáme.

Pythonovský string, který není uložen v kódování Unicode, s sebou nenese žádnou informaci o použitém kódování. Python takový řet>zec chápe jako posloupnost bajtů. Nemá odkud vzít informaci o tom, že velké písmeno k znaku s kódem 249 má kód 217. Například v kódování windows-1250 jde o znaky ůŮ. V jiných kódováních ovšem uvedené kódy mohou patřit zcela jiným znakům, nemusí vůbec tvořit pár malé/velké písmeno a dokonce vůbec nemusí patřit mezi písmena.

ASCII znaky — tj. ty, které mají kód v rozsahu 0 až 127 — představují výjimku v tom smyslu, že mají stejný kód ve všech odvozených kódováních (kódy ASCII znaků jsou zachovány i v Unicode). Metody pro zm>nu velikosti písmen tedy mohou bez problémů nad t>mito znaky fungovat i bez znalosti používaného kódování pro písmena s v>tším kódem. Podívejme se, co Python provede, když bychom v příkladu neuvedli řet>zce v Unicode:

>>> print 'SMÍšenÝ PŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ'.lower()
smÍšenÝ pŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ
>>> print 'SMÍšenÝ PŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ'.upper()
SMÍšENÝ PŘíPAD: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ
>>> print 'SMÍšenÝ PŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ'.swapcase()
smÍšENÝ pŘíPAD: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ
>>> print 'SMÍšenÝ PŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ'.capitalize()
SmÍšenÝ pŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ
>>> print 'ĚŠČŘŽÝÁÍÉ'.islower()
False
>>> print 'ĚŠČŘŽÝÁÍÉ'.isupper()
False

Všechna písmena v rozsahu ASCII jsou správn> převedena, ale všechna ostatní písmena byla ponechána beze zm>ny. Metoda neví, co s nimi, proto je ponechá v původním tvaru. Uv>domte si, že je to přirozené chování metod v případech, kdy zpracovávají znaky, která nejsou písmenem. Existují také písmena, která nemají definováno odpovídající malé nebo velké písmeno (například n>mecké ostré s). Všimn>te si, že predikáty islower() a isupper() zde nepovažují testované řet>ze ani za malá ani za velká písmena.

Unicode řet>zce jsou ovšem speciáln>jší, informačn> bohatší. Písmena jsou určena jednoznačn> a existuje i jednoznačný vztah mezi malým a velkým písmenem (pokud to u znaku dává smysl). Metody pro převody písmen z malých na velká a naopak nemusí zohledňovat žádné nejednoznačnosti. Při použití Unicode se tedy i u ostatních lidských jazyků dostáváme do stejn> pohodové situace, v jaké o podobných řet>zcových operacích píší anglicky mluvící autoři ;-)

Zpracování textu v jazyce VBScript

VBScript vychází z jazyka BASIC. Díky tomu disponuje celou řadou zabudovaných funkcí pro práci s řet>zci. V referenční příručce jsem jich napočítal nejmén> 20 a to jsem nepočítal ty, které se vztahují k zpracování znaků v Unicode.

To znamená, že v jazyce VBScript můžeme s řet>zci d>lat v podstat> vše, co jsme si ukazovali v jazyce Python. V rychlosti si ukážeme jeho možnosti:

Rozd>lování textu

Začneme funkcí Split:

<script type="text/vbscript">
Dim retezec
Dim seznam
retezec = "Toto je seznam slov."
seznam = Split(retezec) ' vrací pole
MsgBox seznam(1)
</script>

Pokud nám rozd>lování řet>zce v místech s bílými znaky (zde mezerami) nevyhovuje, můžeme stejn> jako v Pythonu předepsat hodnotu odd>lovače.

Pro opačný postup zde máme funkci Join — stejn> jako v jazyce Python.

Vyhledávání a náhrada v textu

K vyhledávání podřet>zce slouží funkce InStr, což je zjevn> zkratka z anglického In String, tedy v řet>zci.

<script type="text/vbscript">
Dim s, n
s = "Toto je dlouhý textový řet>zec."
n = InStr(s, "dlouhý")
MsgBox "Slovo 'dlouhý' bylo nalezeno na pozici: " & CStr(n)
</script>

Návratová hodnota obvykle udává pozici v původním řet>zci, na které začíná vyhledávaný podřet>zec. Pokud není nalezen, vrací se nula. (V jazyce VBScript to nepůsobí žádný problém, protože se v n>m indexuje od jedničky. To znamená, že hodnota nula nereprezentuje platnou hodnotu indexu.) Pokud má řet>zec hodnotu Null, vrací se hodnota Null. Tím se pon>kud komplikuje ov>řování, zda nedošlo k chyb>.

Stejn> jako v Pythonu můžeme i v jazyce VBScript vymezit část původního řet>zce, která se má prohledávat. Můžeme uvést index, od kterého se má začít vyhledávat:

<script type="text/vbscript">
Dim s, n
s = "Toto je dlouhý textový řet>zec."
n = InStr(6, s, "dlouhý")  ' Hledej od pozice 6.
MsgBox "Slovo 'dlouhý' bylo nalezeno na pozici: " & CStr(n)
</script>

Narozdíl od Pythonu můžeme v jazyce VBScript předepsat také to, zda se mají při vyhledávání rozlišovat velká a malá písmena, či nikoliv. Pokud to neurčíme, velká a malá písmena se rozlišují.

Náhrady textu se provád>jí prostřednictvím funkce Replace:

<script type="text/vbscript">
Dim s
s = "Příšern> zeleňoučký kůň úp>l ďábelské ódy."
MsgBox Replace(s, "zeleňoučký", "žluťoučký")
</script>

Poslední nepovinný argument určuje, kolik výskytů vyhledávaného vrorku se má nahradit. Pokud neurčíme jinak, nahrazují se všechny výskyty. Můžeme určit i počáteční pozici pro prohledávání a náhradu, jako u výše zmín>né funkce InStr.

Zm>na velikosti písmen

Zm>nu velikosti písmen provádíme v jazyce VBScript funkcemi UCase a LCase. Ekvivalent pythonovské metody capitalize() tady nenajdeme.

<script type="text/vbscript">
Dim s
s = "SMÍšenÝ PŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ"
MsgBox LCase(s)
MsgBox UCase(s)
</script>

To je vše, čím se budeme v této učebnici zabývat. Pokud se chcete dozv>d>t více, projd>te si seznam funkcí v nápov>d> k VBScript.

Poznámka překladatele: V tomto případ> (narozdíl od stejného řet>zce v pythonovském příkladu, kdy řet>zec nebyl uveden v Unicode) dojde ke korektnímu převodu na malá i velká písmena i u znaků s diakritikou. Je to dáno tím, že VBScript s řet>zci jednoznačn> spojuje určité kódování. Pokud je skript vložen do HTML souboru, pak bývá kódování předepsáno v jeho hlavičce. Stejn> je tomu i u XML souborů. Pokud kódování není předepsáno vůbec, pak VBScript předpokládá, že se používá kódování definované v systému.

Zpracování textu v JavaScript

JavaScript je z našich tří jazyků pro zpracování textu vybaven nejhůře. I přesto jsou základní operace do určité míry podporovány. Ve srovnání s jazyky Python a VBScript jazyk JavaScript trpí nedostatky, které tkví spíše jen v množství "cingrlátek". JavaScript tato omezení kompenzuje silnou podporou regulárních výrazů. (Budeme se jimi zabývat v jednom z dalších témat.) Regulární výrazy výrazn> rozšiřují možnosti, které poskytují výše zmín>né primitivní funkce, ale platíme za to zvýšením složitosti.

JavaScript, stejn> jako Python, využívá k manipulaci s řet>zci objektov> orientovaný přístup. Všechny operace se provád>jí prostřednictvím metod třídy String.

Rozd>lování textu

Rozd>lování textu se provádí metodou split():

<script type="text/javascript">
var seznam, retezec = "Toto je krátký řet>zec";
seznam = retezec.split(" ");
document.write(seznam[1]);
</script>

Povšimn>te si, že JavaScript vyžaduje zadání odd>lovacího znaku. Neexistuje zde žádná předdefinovaná hodnota. Odd>lovač může být definován i regulárním výrazem, takže operace rozd>lení může být velmi důmyslná.

Vyhledávání textu

K vyhledávání textu se v jazyce JavaScript používá metoda search():

<script type="text/javascript">
var retezec = "Na Nilu ibisi kvílili bílí...";
document.write("'ibisi' se nachází na pozici: " + retezec.search(/ibisi/));
</script>

zmatky řet>zec/vzorek

Znovu platí, že vyhledávaný řet>zcový vzorek je ve skutečnosti regulárním výrazem. To znamená, že vyhledávání může mít velmi důmyslná pravidla. Na druhou stranu neexistuje možnost vymezit část původního řet>zce, která se má prohledávat, zadáním počáteční pozice (ačkoliv i tuto možnost můžeme simulovat prostřednictvím regulárního výrazu).

JavaScript podporuje i jinou vyhledávací operaci s mírn> odlišným chováním. Nazývá ze match() ([meč], zde ve smyslu odpovídat, pasovat). V této částí se metodou match() nebudeme zabývat.

Náhrada textu

zmatky řet>zec/vzorek

K nahrazování textu se používá metoda replace().

<script type="text/javascript">
var retezec = "Kočka leze dírou, pes dveřmi...";
document.write(retezec.replace(/dveřmi/, "oknem"));
</script>

A znovu připomeňme, že vyhledávaný vzorek může být zadán regulárním výrazem. Myslím, že už vidíte ten obecný vzor. Operace náhrady nahrazuje všechny výskyty vyhledávaného vzorku a, pokud mohu říci, neexistuje žádný způsob, jak dosáhnout náhrady pouze jednoho výskytu, aniž byste řet>zec nejdříve rozd>lili a pak jej op>t pospojovali dohromady.

zmatky řet>zec/vzorek, počet náhrad

Zm>na velikosti písmen

Pro zm>nu velikosti písmen máme k dispozici dv> funkce: toLowerCase() a toUpperCase().

<script type="text/javascript">
var retezec = "SMÍšenÝ PŘípad: >ščřžýáíéúůó ĚŠČŘŽÝÁÍÉÚŮ";
document.write(retezec.toLowerCase()+ "<br>");
document.write(retezec.toUpperCase()+ "<br>");
</script>

K t>mto funkcím můžeme st>ží co dodat. Jednoduchým způsobem provád>jí jednoduchou činnost. JavaScript — narozdíl od ostatních jazyků, o kterých se bavíme — nabízí řadu speciálních textových funkcí pro zpracování HTML. Odhaluje tím své kořeny jazyka určeného pro programování ve webovém prostředí. Nebudeme se jimi zabývat. Popis naleznete ve standardní dokumentaci.

Tím uzavíráme pohled do sv>ta zpracování textu. Doufám, že jste tím získali nástroje, které potřebujete ke zpracování textu ve vašich projektech. Záv>rečná rada zní: Při zpracování textu si vždy pročt>te dokumentaci zvoleného jazyka.Řešení nejzákladn>jších programátorských úloh je často podpořeno mocnými nástroji.

Zapamatujte si

Pokud vás napadne, co by se dalo na překladu této kapitoly vylepšit, zašlete e-mail odklepnutím Tím budou do dopisu automaticky vloženy informace o tomto HTML dokumentu.

$Id: cztuttext.html,v 1.6 2005/10/20 20:52:40 petr Exp $