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 $