9. fejezet: Szövegkezelés és példák
Ebben a fejezetben megmutatom, hogyan lehet a szöveget karakterenként kezelni. Ezen kívül, a korábban tanultak felhasználásával, már összetettebb feladatokkal is találkozhatsz, melyek általános programozási technikákat mutatnak be. A továbbiakban az ilyen példák egyre gyakoribbak lesznek, tehát akkor is érdemes egy fejezetet elolvasnod, ha éppen az a téma (most a szövegkezelés) nem érdekel.
A szöveg karakterei
Egy string típusú változó úgy viselkedik, mint egy karakterekből álló tömb. Így s[2]
a string második karakterét jelenti. Ha minden karaktert fel szeretnénk dolgozni, szükségünk lesz a string hosszára: ezt a length
függvény adja meg.
A következő példa kiírja a szöveget függőlegesen (soronként egy karaktert):
Var s:string; i:integer; BEGIN write('Írj be valamit: '); readln(s); for i:=1 to length(s) do writeln(s[i]); write('nyomj entert'); readln; END.
Figyelem! Ezek a példák ékezetes karakterekkel csak úgy fognak működni, ha a fájl kódolását CP852-re állítottad! (2. fejezet). Ennek okáról és az utf-8 kódolásról később, a grafikus felület kezelésénél lesz szó.
Kidolgozott példa: magánhangzóvizsgálat
Számoljuk meg egy string magánhangzóit! A ciklusunk ilyesféle feltételt tartalmazna:
if (s[i]='a') or (s[i]='A') or (s[i]='á') or (s[i]='Á')...
ez így, a kis- és nagybetűket figyelembe véve, nagyon hosszadalmas lenne. Ha azonban a magánhangzók listája szerepelne egy változóban, csak azt kellene megvizsgálni, hogy az adott karakter szerepel-e ebben.
m:='öüóeuioőúaéáűíÖÜÓEUIOŐÚAÉÁŰÍ'
Hogyan állapítsuk meg, hogy a szövegünk s[i]
karaktere szerepel-e m
-ben? Egy ciklussal végiglépkedünk m
összes karakterén, amíg nem találunk egyezést s[i]
-vel, vagy m
végére nem érünk. Ez most nem for-ciklus lesz, mert nem tudjuk előre, meddig kell számolnia. Az elöltesztelős ciklusnak viszont a végrehajtás feltételét kell megadni, ami az, hogy nem találtunk egyezést és nem értünk a végére.
j:=1;
while (j<=length(m)) and (s[i]<>m[j]) do j:=j+1;
A ciklus kétféleképpen állhat le. Ha a második feltétel nem teljesül, akkor s[i]
szerepel m
-ben a j
. helyen, vagyis magánhangzó. Ha az első feltétel nem teljesül, akkor j>length(m)
, vagyis végigmentünk m
-en, de nem találtunk egyezést
Ha végig nincs egyezés, akkor az utolsó lépésben j=length(m)
, és s[i]<>m[j]
, tehát j
nő eggyel. A következő vizsgálatnál az első részfeltétel hamis lesz, hiszen j>length(m)
. Mi a helyzet a második feltétellel? Az értelmetlen, mert m
-nek nincs annyiadik karaktere. Nem fog ez hibát okozni a programban?
Nem. A Pascal (az alapbeállítások használata esetén) az AND-del összekapcsolt feltételeket úgy vizsgálja, hogy ha az első feltétel hamis, a másodikat már nem ellenőrzi (mert az eredmény úgyis hamis). Hasonlóképpen, az OR-ral összekapcsolt két feltétel közül ha az első igaz, a másodikat már nem vizsgálja. Ezért nem mindegy, hogy a feltételeket milyen sorrendben írjuk be.
Végül a magánhangzóvizsgálatot betesszük egy mgh
nevű függvénybe. A függvényérték típusa most boolean
lesz (igaz, ha a karakter magánhangzó).
Var s:string; i,c:integer; Function mgh(c:char):boolean; var m:string; j:integer; begin m:='öüóeuioőúaéáűíÖÜÓEUIOŐÚAÉÁŰÍ'; j:=1; while (j<=length(m)) and (c<>m[j]) do j:=j+1; mgh:=(j@lt;=length(m)); end; BEGIN write('Írj be valamit: '); readln(s); c:=0; for i:=1 to length(s) do if mgh(s[i]) then c:=c+1; writeln(c,' magánhangzó volt benne.'); write('nyomj entert'); readln; END.
Magyarázat: az eljárásnak a vizsgálandó karaktert paraméterként adjuk át, ez c lesz, nem keverendő a főprogram számláló c-jével. mgh igazságértéke abból derül ki, hogy j nem lépte túl m hosszát.
További hasznos szövegkezelő lehetőségek
A Pascal sok szövegkezelő függvényt és eljárást ismer, amelyekkel az egyes karakterek vizsgálatánál gyorsabban megoldhatjuk a feladatokat.
Pos(string1,string2)
kereső függvény megadja, hogy string1 hányadik karakternél kezdődik string2-ben. 0 lesz a végeredmény, ha nem szerepel benne. Az első előfordulás számít, tehát pos('ép','szép kép')
eredménye 3 lesz.
Így az előző program függvénye egyszerűbben is megoldható, ciklus nélkül:
mgh:=(pos(c,m)>0)
Copy(string,szám,darab)
függvény eredménye olyan részszöveg, mely string szám-adik karakterétől kezdődik, és darab hosszú. Vagyis copy('malac',3,2)
eredménye a 'la' string.
Delete(string,szám,darab)
eljárás, mely módosítja string változót (változóparaméter!) úgy, hogy töröl belőle a szám-adiktól kezdve darab karaktert.
Insert(mit,mibe,szám)
eljárás, mely mibe string típusú változóba szám-adik karakterétől beszúrja mit szöveget.
Ne feledkezzünk meg a stringek közötti +
műveletről, mely az összefűzésüket jelenti.
Ez a példa kitörli S
stringből az összes kettőspontot:
while pos(':',S)>0 do delete(S,pos(':',S),1);
Ez pedig, ha NEV
egy "vezetéknév szóköz keresztnév" formátumú string, K
-ba beteszi a keresztnevet.
K:=copy(NEV,pos(' ',NEV)+1,length(NEV)-pos(' ',NEV));
Feladatok
34. Írj programot, amely a beírt szövegben megszámolja az "e" betűket!
35. írj programot, amely a B változóba beteszi az A változóban tárolt szöveg megfordítását!
36. Írj programot, amely a beírt szöveget szavanként írja ki!
37. Írj programot, amely a megadott stringből törli a fölösleges szóközöket (ahol egymás mellett több van)!
38. Írj programot, amely a beírt szövegből csak a mássalhangzókat írja ki! Használd benne a fenti mgh függvényt.
39. Írj programot, amely a beírt szöveget "madárnyelven" írja ki! (pl. tulipán->tuvulivipáván)
40. Készíts függvényt, amelynek eredménye a megadott szöveg, az összes "j"-t "ly"-ra cserélve!