09. 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<=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!
megoldás
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!

Comments