Znaky a řetězce

Ve 3. lekci jsme mezi typy proměnných uvedli i typy char (= znak) a string (=řetězec) a v průběhu dalších lekcí jsme je používali (především string, protože například to, co vepíšeme do Editu nebo vypisujeme do nějaké komponenty (Label, Edit, List) jsou řetězce). Připomeňte si funkce inttostr, floattostr, strtoint, strtofloat , které jste často využili k převodům mezi čísly a řetězci, nebo operaci + pro spojování řetězců (například pro výpisy spojující texty a čísla převedená na texty). V této lekci přidáme ještě další možnosti pro práci se znaky ale především řetězci.


Typ char (znaky)

Proměnné, do kterých chceme ukládat jedno písmeno (znak) jsou typu char.
Každému znaku je přiřazeno číslo, takzvaný ASCII kód, pomocí kterých jsou znaky uspořádané. Např. znak a má ASCII kód 97, zatímco znak A má 65, proto při porovnávání znaků by A bylo "menší" než a. Pro práci se znaky slouží například tyto funkce:
ord(znak) - určí ASCII kód znaku, např. ord(a) je 97
chr(číslo) - určí znak daný ASCII kódem, např. chr(65) je znak a
upcase(znak) - převod malého písmena na velké

Pro výpis tisknutelných znaků (ASCII od 32 do 255) do ListBoxu můžete použít tento příkaz:
for cislo:=32 to 255 do listbox1.items.Add('ASCII: '+inttostr(cislo)+' znak:'+chr(cislo));

Pokud chcete použít znak v příkazu, musíte jej zapsat do uvozovek, aby byl odlišený od názvu proměnné (nebo později procedury apod.), například:
if odpoved='a' then Edit1.Text:='výborně';


Typ string (řetězec)

Proměnnou typu string jsme již deklarovali (definovali) mnohokrát, pokud dopředu víme, kolik znaků bude řetezec obsahovat, můžeme proměnnou pro úsporu paměti definovat takto:
slovo :string[20] {definice proměnné, která může obsahovat jen 20 znaků}

Prázdný řetězec se zapisuje pomocí dvou apostrofů vedle sebe:
slovo:=''

Kromě operací s celými řetězci, můžeme pracovat také s jednotlivými písmeny řetězce, v hranaté závorce uvádíme pořadí (index) písmene (jsou číslovaná od 1), např.:
a:=slovo[5] - do proměnné a uloží páté písmeno proměnné slovo
slovo[4]:='x' - čtvrtý znak proměnné slovo bude nahrazeno písmenem x

Další funkce, které pro práci s řetězci můžete použít:
length(retezec) - délka řetězce
copy(retezec,od,pocet) - vrací část řetězce retezec od indexu od délky pocet znaků,
například: a:=copy(retezec,1,3) - do proměnné a se uloží první tři znaky z proměnné retezec
delete(retezec,od,pocet) - smaže v řetězci retezec od indexu od pocet znaků
insert(retezec,slovo,od) - vkládá retezec do slovo od indexu od
pos(retezec,slovo) - zjišťuje, od kterého indexu začíná retezec ve slovo


Projekt Šibenice

Práci s řetězci využijeme k naprogramování známé hry Šibenice, ve které hráč hádá utajené slovo tak, že postupně zkouší písmena, která by ve slově mohla být. Pokud najde písmeno ze slova, potom se mu do hádaného slova doplní.
Jak je vidět z obrázku, stačí dvě tlačítka na spuštění hry a zkontrolování písmene, Edit na vložení písmene a Label nebo Edit na vypisování hádaného slova.

V následujícím programu jsou použity tyto proměnné:
slovo: string; {slovo, ktere se hada}
n: integer; {promenna pro for cyklus}
pismeno: char;{vlozene pismeno}
vypis: string;{retezec, ktery se prubezne vypisuje}
nasel: integer;{pomocna promenna pro zaznamenani toho, zda se pismeno vyskytuje ve slovo}

Úvodní procedura bude na tlačítku Nová hra, do proměnných vypis a slovo se vloží příslušné řetězce a vypis se zobrazí v Labelu:
procedure TForm2.Button2Click(Sender: TObject);
begin
vypis:='?????';
slovo:='koule';
Label1.Caption:=vypis;
end;

Na tlačítku pro kontrolu vloženého písmene by mohla být následující procedura:
procedure TForm2.Button1Click(Sender: TObject);
begin
pismeno:=Edit1.text[1];
nasel:=0;
for n:=1 to 5 do
   if pismeno=slovo[n] then begin vypis[n]:=pismeno; nasel:=1; end;
if nasel=1 then showmessage('skvele') else showmessage('bohuzel');
Edit1.Text:='';
label1.Caption:=vypis;
if vypis=slovo then showmessage('uhodl jsi cele slovo');
end;
Vysvětlení snad není mnoho zapotřebí - po řádcích:
- do proměnné pismeno se uloží první znak z Edit, neboli zkoušené písmeno
- vynuluje se proměnná nasel
- následuje for cyklus, ve kterém se automaticky mění proměnná n od 1 do 5 a pro každou hodnotu (tedy pětkrát) se vykoná následující příkaz if
- pro každé n od 1 do 5 se zjišťuje, jestli se proměnná pismeno rovná n-tému písmenu hádaného slova, jestliže ano, potom se v proměnné vypis nahradí n-tý otazník správným písmenem a do proměnné nasel se uloží 1
- for cyklus skončí, podíváme se jestli písmeno bylo správné (nasel=1), jestliže ano, vypíše se jedna hláška, jinak druhá hláška
- vyprázdní se Edit pro vložení dalšího písmene
- do Labelu se vypíše nová hodnota proměnné vypis - jestliže je uhodnuto celé slovo, vypíše se závěrečná hláška, jupííí :-))

Práci s řetězci můžeme využít například pro řešení jedné z úloh krajského kola programování z roku 2010 pro výpočet tzv. superciferného součtu, kdy se počítá ciferný součet tak dlouho, dokud není menší než 10. Například číslo 1234567 má ciferný součet 1+2+3+4+5+6+7 = 28, ten je větší než 9, proto se počítá dál ciferný součet čísla 28, to je 2+8 = 10, i tento součet je větší než 9, počítá se tedy další, teprve ciferný součet 1+0 = 1 je menší než 9 a je výsledným superciferným součtem.

Superciferný součet

Prostředí programu je velmi prosté - jeden edit pro zadání čísla, tlačítko pro spuštění výpočtu a label do kterého se vypíše výsledek. Jednou novinkou, kterou jsem v řešení použil je příkaz
while (podmínka) do příkaz - dokud je splněná podmínka, dělej příkaz

Pro zápis čísla je možné použít proměnnou typu string, ta je omezená na 256 znaků, pokud bychom chtěli zapsat delší číslo, můžeme použít například typ ansistring, do kterého se vejde více než miliarda znaků (viz nápověda Delphi, to by se zase nevešlo do Editu a museli bychom použít Memobox).
K výpočtu stačí jedna poměrně jednoduchá procedura:
procedure TForm2.Button1Click(Sender: TObject);
begin
cislo:=Edit1.Text;
cif_souc:=10;

while cif_souc>9 do
begin
cif_souc:=0;
for i:=1 to length(cislo) do
begin
cif_souc:=cif_souc+strtoint(cislo[i]);
end;
if (cif_souc>9) then begin cislo:=inttostr(cif_souc);end;
end;
Label4.Caption:=inttostr(cif_souc);
end;

Do proměnné cislo se uloží text z Editu a do proměnné cif_soucet vložíme číslo větší než 9, aby se aspoň jednou vykonal následující příkaz while. Dokud bude aktuální ciferný součet větší než 9, uloží se do něj nejdříve nula, potom se do něj nasčítají ve for cyklu číslice aktuálního čísla. Pokud bude ciferný součet větší než 9, uloží se do proměnné cislo (nahradí předešlé číslo) a vše se opakuje, dokud je ciferný součet větší než 9.

Aplikace ukládej do složky s názvem lekce12 .

Úkoly:

Základní úloha:

Vytvoř aplikaci Šibenice podle textu lekce ale s jiným slovem (viz ukázka ). Doplň ji o vypisování počtu pokusů průběžně i na konci.


Úlohy na plus (za každou jedno plus):

1. Vytvoř jednoduchou hru pro dva hráče - první hráč zadá slovo, které druhý hráč hádá poté, co ho program vypíše s hvězdičkami místo každého druhého písmene.

2. Doplň základní úlohu o další dvě slova.


Úloha na jedničku:

Zadání úlohy ze soutěže PC-ák 2006 (počítačová soutěž pro žáky základních škol SPŠE a VOŠ Pardubice):
Zadáme výsledné časy závodníků běhu na 3000 metrů jako řetězce obsahující počet minut a počet sekund oddělené dvojtečkou, např. "12:35" nebo "9:54" apod. Program vypočte průměrný čas a zobrazí jej opět ve stejném formátu jako zadané časy.
Takto vypadalo soutěžní hodnocení této úlohy:
Zadávání vstupních hodnot v cyklu s vhodným ukončením zadávání, např. zadáním prázdného řetězce nebo jiné vhodné řešení zadání hodnot ............ 5 bodů
Rozdělení řetězce obsahujícího min a sec oddělené dvojtečkou na dvě části:
a) Rozdělení řetězce podle pozice dvojtečky (časy mohou být zadány "12:35" nebo "9:54") ............ 8 bodů
b) Rozdělení řetězce bez vyhledání pozice dvojtečky (časy musí být zadány "12:35" nebo "09:54") ............ 5 bodů
Výpočet počtu sekund z řetězců obsahující počet minut a počet sekund:
a) Převedení řetězců na čísla a vypočtení počtu sekund ............ 5 bodů
b) Řešení bez znalostí převodu řetězců na čísla (časy musí být zadány jako čísla - počet min a počet sec) ............ 1 bod
Výpočet průměrné hodnoty času ............ 5 bodů
Přepočet času na mm:ss :
a) Řešení přepočtu a správný výpis včetně případného doplnění sec na dvě cifry, např. 9:08 ............ 5 bodů
b) Řešení přepočtu a výpis bez případného doplnění sec na dvě cifry, např. 9:8 nebo 9min a 8s ............ 3 body
Estetické zpracování programu ............ 2 body


Úloha pro experty:

Doplňte úlohu z lekce o průběžné vykreslování "oběšence".