Zpracování textů

Omlouvám se, pro nedostatek času bude dopracováno dodatečně.

Jenom abych nezapoměl, co sem patří, bodově:

function InputBox ( const Caption, Prompt, Default : string ) : string;

procedure ShowMessage ( const Text : string ) ;

Práce s řetězci.

Deklarace.

Řetězce nadeklarujeme jako typ string. Delphi zná více druhů řetězců (shortstring, ansistring, widestring pro přesnou specifikaci, pchar pro spolupráci s moduly vytvořenými v jazyce C, ale pro ten neplatí dále používané funkce).

var
  s : string;

Jako příklad uložení do paměti si nyní popíšeme shortstring. String (řetězec) představuje vlastně vektor (jednorozměrné pole), ve jehož prvcích jsou umístěny jednotlivé znaky. V prvním znaku je délka řetězce (počet znaků, které budou následovat). Obrázek naznačuje následující tabulka:

#4 'A' 'l' 'í' 'k' ? ? ? ? ? ?

Maximální délka řetězce v tomto formátu je tedy 255 znaků. V uvedeném případě řetězec obsahuje jen čtyři znaky, což je napsáno v nulté položce. V Pascalu lze zapsat do programu jednotlivý znak buď mezi apostrofy, nebo napsat "mřížku" (dvojitý křížek, jako v uvedeném případě) a jeho číslo. Otazníky v tabulce označují neznámou hodnotu - každá buňka paměti je po zapnutí počítače nějak náhodně nastavena.

Ne vždy je třeba rezervovat pro řetězec celých maximálních 255 buněk. Maximální délku řetězce pak zapíšeme do deklarace:

var
  s : string[20];

Při použití musíme dát pozor, že není zapnuta žádná ochrana paměti. Pokud píšeme mimo meze, které jsme si nadeklarovali, pak zřejmě poškozujeme jiné proměnné - u lokálních proměnných bohužel návratové adresy (program se v tom případě bez varování zhroutí).

spojování řetězců, porovnávání velikosti řetězců relačními operátory (ne funkcí).

Řetězci můžeme přiřadit hodnotu obvyklým příkazem přiřazení. Mějme řetězce a, b a c. Pak můžeme zapsat:

a := b;

a také můžeme uložit do řetězce a součet obou řetězců:

a := b + c;

Součet vznikne tak, že se za konec prvního řetězce připojí celý druhý řetězec (přesněji se jedná o spojení).

Často také potřebujeme zadat počáteční hodnotu řetězce, nebo místo použití proměnné jej na dané místo programu vypsat ručně. V Pascalu se v tom případě řetězec zapíše mezi apostrofy:

a := 'Alík';

Pokud řetězec obsahuje znaky, které nelze zapsat (například řídící znaky ASCII), lze je zadat výše uvedenou konvencí s mřížkou. Následující příklad obsahuje tři čísla, oddělená tabulátorem (znak číslo 9):

b := '3,29'#9'2,56'#9'4,12';

Všimněte si, že znak, zadávaný jeho kódem, je jaksi mimo apostrofy. Samotný apostrof lze zapsat jako dva apostrofy. Mezera se zde ovšem (mimo apostrofy) nesmí objevit, protože funguje jako oddělovač a rozdělila by řetězec na dva. Nelze ani přerušit zápis na konci řádku obráceným lomítkem jako v C++ a pokračovat na dalším řádku. V krajním případě můžete použít sčítání s rizikem, že se bude provádět až za chodu programu (zpravidla ale Borland překládá dobře).

Poslední, na co někdy nejsou třeba funkce, je porovnávání dvou řetězců za využití relačních operátorů. Například

a < b

vrací true, pokud a je menší než b. Porovnání probíhá tak, že se porovnají první dva znaky. Pokud mají stejnou hodnotu, porovnají se další dva, dokud se nerozhodne. Pokud před dosažením rozhodnutí jeden z řetězců skončí (je celý stejný, jako začátek druhého), je kretší řetězec považován za menší. Pokud skončí oba najednou, jsou řetězce stejné (jak překvapující). Při tomto porovnání jsou tedy všechna písmena malé abecedy větší než písmena velké abecedy. O třídění s ohledem na češtinu pojednáme o několik kapitol později.

funkce copy

Pokud chceme přenést do jiného řetězce jen část řetězce, můžeme použít funkci copy. Má tři parametry - první je řetězec, ze kterého chceme kopírovat, druhý určuje pořadí znaku, kterým chceme začít, třetí pak počet znaků k přenesení. Pokud například zadaný řetězec má dvacet znaků a my zadáme parametry 5 a 4, přenesou se znaky 5 až 8 (funkce vrací řetězec o délce 4 znaky). Jiná situace nastane, pokud takové znaky v řetězci nejsou. Pokud má kopírování začít znakem, který již v řetězci není, vrací funkce prázdný řetězec. Pokud je od tohoto znaku dále méně znaků, než požadujeme přenést, přenese se celý zbytek. Toho se využívá, když chceme kopírovat řetězec od daného místa až do konce - zadáme větší číslo, než byl řetězec deklarován.

Například

s:=copy('Přeji dobrý den',7,5);

nastaví do s hodnotu 'dobrý'.

funkce length

Vrací skutečnou délku řetězce. Pro pascalské typy (string, shortstring...) vrací údaj z prvního či prvních dvou znaků.

Například 

l :=length('Přeji dobrý den'); 

  nastaví do l hodnotu 15.

funkce pos

Často řešíme situaci, kdy musíme zkopírovat část řetězce, která následuje za nějakým znakem (například v adrese souboru za lomítkem). K tomu slouží funkce pos, která umí v řetězci hledat nejen znak, ale celý podřetězec (skupinu znaků). Pokud například víme, že v řetězci s je podřetězec 'txt', vrací jeho pozici výraz

pos('txt', s)

Jako první parametr se uvádí hledaný podřetězec, jako druhý řetězec, ve kterém se má hledat. Pokud text nalezne, vrací pozici prvního znaku. Pokud nikoli, vrací nulu. Této funkce lze proto použít i v případě, že zkoumáme, zda se v řetězci vyskytlo nějaké slovo. Pokud je například hledané slovo v řetězci a a prohledáváme řetězec s, můžeme napsat

if pos(a,s)>0 then showmessage('Našel jsem!');

procedura delete

Jako procedura nevrací nic, ale mění hodnotu zadaného řetězce. Jejím prvním parametrem proto musí být řetězec, ze kterého se počínaje znakem, jehož pozice je v druhém parametru, odstraní tolik znaků, kolik je uvedeno ve třetím parametru. Například

s := 'Přeji dobrý den';
delete(s,7,5);

skončí s hodnotou 'Přeji  den' (dvě mezery za sebou) v proměnné s typu řetězec (string).

Vyřešte příklad: Edit1, sem napíšeme větu, Edit2, Tlačítko; když se stiskne tlačítko, první slovo z věty se přesune do Edit2 a z Edit1 se umaže.

procedura insert

Vloží hodnotu prvního parametru do řetězcové proměnné, zadané jako druhý parametr, počínaje pozicí, zadanou jako třetí parametr - slovo inzert znamená, že zbylé znaky se posunou. Například příkaz

s:='Přejeme dobrý den';
insert('velmi',s,9);

skončí s hodnotou 'Přejeme velmidobrý den' (bez mezery) v proměnné s typu řetězec (string).

Komponenta memo

V praxi velmi často potřebujeme pracovat nikoli s jedním řetězcem, ale s celým textem. Text si můžeme představit tak, že každý řetězec představuje jeden řádek (konce řádků pak nejsou zaznamenány nikde). Delphi takovou představu textu podporuje zavedením typu "TStrings". Nás ovšem nejvíce zajímá komponenta Memo, která umožňuje tyto řetězce zobrazit a modifikovat uživatelem hotového programu (představuje tím jakýsi malý editor textu).

TMemo.ScrollBars
- pokud mají být k dispozici svislý a vodorovný posuvník, pak se zde musí zapnout. Pokud chybí svislý, bude třeba text posouvat klávesami pro pohyb kursoru (nahoru, dolů).
- pozor, pokud chybí vodorovný, text se při načtení (či zapsání) zalomí dle okamžité šířky komponenty Memo. Tento zásah (doplnění konců řádků) je nevratný.

TMemo.Lines
- komponenta typu TStrings, přes kterou je dostupná většina funkcí mema. Lze napsat například Memo1.Lines[5] nebo Memo1.Lines[j], není třeba vypisovat správně celý odkaz na příslušný řádek, např. Memo1.Lines.Strings[5] .
- řádky jdou číslované od nuly. jejich počet je v TMemo.Lines.Count (poslední má index o jednu nižší, než vrací tato funkce)

TMemo.Lines.Add
- řetězce jsou dynamické. Je-li třeba přidat jeden řádek, učiňte tak buď touto funkcí, která přidává na konec seznamu (jako poslední řádek textu), nebo funkcí TMemo.Lines.Insert, která vkládá řádky (funkce add se používá pro výpisy a podobně, kde řádky přibývají vždy na konci analogicky existuje funkce TMemo.Lines.Delete pro smazání n-té řádky).

TMemo.Lines.Clear
- smazání všech řetězců (a tím obsahu celého mema). Vhodné, pokud memo chcete použít pro další výpis, nebo načíst nový obsah ze souboru.

TMemo.Lines.LoadFromFile
- načte textový soubor do řádků položky memo počínaje nultou. Pokud je načítaných řádků více, je výsledná délka mema daná počtem načítaných řádků.

TMemo.Lines.SaveToFile
- opak, uložení textu do souboru. Viz poznámka Scrollbars (již pouhé načtení textu jej může modifikovat, takže ani bezprostředním uložením neuložíme to samé).


SaveDialogOpenDialogTOpenDialog.Execute, TSaveDialog.Execute
- nejsnazší způsob, jak se uživatele zeptat, kam se bude ukládat soubor, je spustit TSaveDialog. Naleznete ji na liště "dialogs". Tato komponenta se za chodu programu nezobrazí, ale musí se zavolat pomocí její funkce Execute. Po proběhnutí zkontrolujeme její hodnotu - vrací True, pokud bylo vybráno jméno souboru (dialog ukončen tlačítkem OK), nebo False, pokud bylo okno uzavřeno, aniž by se dosáhlo nalezení a potvrzení jména souboru (uzavřením okna, tlačítkem "Zrušit"). Pokud funkce vrátila True, je výsledek uložen v proměnné TOpenDialog.FileName (včetně cesty, je-li třeba).

- ustálený obrat je

if OpenDialog1.Execute
then Memo1.Lines.LoadFromFile(OpenDialog1.FileName);

Zkuste jej použít v nějakém programu. Analogicky lze použít SaveDialog a SaveToFile pro uložení souboru.

Při vytváření programu pomocí Object Inspectoru nebo při běhu můžeme nastavit následující parametry dialogového okna:

property Filter
"rozkliknutím" lze zobrazit okno, kde lze nastavit několik různých filtrů, a tím řídit, které soubory bude nově vytvářený program "vidět". V levém sloupečku je jméno filtru, v pravém jeho maska pro filtrování souborů. Tabulka může mít například následující obsah:

Textové soubory *.txt
Inicializační soubory *.ini
Všechny soubory *.*

property DefaultExt
Pokud zde nějakou nadefinujete, pak se použije, pokud uživatel při použití programu v dialogovém okně žádnou nezadá. Například soubor "pokus,doc" je zadán bez přípony (čárka, ne tečka) a bude mu doplněna, zatímco soubor "seznam.uživatelů" je zadán s příponou a další se již nepřidá.

propery DefaultDir
Je-li vyplněno, pak se při otevření dialogového okna objeví obsah tohoto adresáře.

příklad: Umístěte si na formuláři memo, savedialog, opendialog, 2 tlačítka, zkuste například vytvořit program pro editaci .ini souborů (např. D:\windows\*.ini).