13. hét: állapotgépek

Czirkos Zoltán · 2021.05.31.

Gyakorlófeladatok az előadás anyagához kapcsolódóan.

1. Állapotgépek

Kettős mássalhangzók

Készíts kettős mássalhangzó számláló programot!

a.) Írj programot, mely a billentyűzetről érkező karaktereket figyeli, és megszámolja a beírt szövegben található "ly" és "sz" kettős mássalhangzójú betűk számát. A szöveget nem tárolhatja el a program, csak a találatok számát. A szöveg beírása és a számlálás a fájl vége jellel véget ér, ekkor a program írja ki tételesen az összeszámlált mennyiségeket.

b.) Az előbbi programot egészítsd ki azzal, hogy a "zs" betűket is számolja, de vigyázz: egy leütött karaktert csak egyetlen kettős mássalhangzójú betűhöz számold, méghozzá az elsőhöz (pl. "egészség": 1 db "sz", 0 db "zs")!

Mondatszámláló

Adja meg egy tetszőleges, standard bemenetről érkező szövegről, hogy hány mondat van benne. Mondatnak tekintünk minden olyan karaktersorozatot, amelyik nagybetűvel kezdődik, ponttal, kérdőjellel vagy felkiáltójellel végződik.

HTML formátum

Írj programot, amelyik HTML formátumú fájlból eltávolítja a szedés jelöléseit, vagyis a <…> szerű karaktersorozatokat, ezzel többé-kevésbé olvashatóvá téve azt normál szövegként. (Például <br>, <title>).

Szavak

Írj állapotgépes programot, amely külön-külön sorokban nyomtatja ki a bemenetére érkező szavakat! Ha a szavak között több szóköz van, akkor ne legyenek üres sorok a kimeneten!

Szmájli számláló I.

Írj állapotgépes programot, amely a szabványos bemenetről olvasott szövegben megszámolja a szomorú :( és a vidám :) szmájlikat. A számlálás után kiírja, hogy a szöveg vidám, szomorú vagy közömbös, azaz több, kevesebb vagy ugyanannyi :) volt, mint :(.

Tervezd meg az állapotgépet állapot- és tevékenységtáblával, utána írd meg a programot! A programra csak akkor jár pont, ha állapotgépes és a leírt állapottáblát valósítja meg.

Megoldás
: ( ) többi
alap →kp - - -
kp - szom++, →alap vid++, →alap →alap

Szmájli számláló II.

Írj állapotgépes programot, amely a szabványos bemenetről olvasott szövegben megszámolja a szomorú :( és a vidám :) szmájlikat. A számlálás után kiírja, hogy a szöveg vidám, szomorú vagy közömbös, azaz több, kevesebb vagy ugyanannyi :) volt, mint :(. A szmájlik zárójelenként egynek számítanak, vagyis :))) három vidámat, :(( két szomorút jelent.

Tervezd meg az állapotgépet állapot- és tevékenységtáblával, utána írd meg a programot! A programra csak akkor jár pont, ha állapotgépes és a leírt állapottáblát valósítja meg.

Megoldás
: ( ) többi
alap →kp - - -
kp - szom++ vid++ →alap

Sz és zs számláló

Írj állapotgépes programot, amely a szabványos bemenetről olvasott szövegben megszámolja az „sz” és a „zs” betűket! (Hosszú ssz és zzs is egynek számítanak, azokkal külön nem kell foglalkozni.) A számlálás után írd ki a szabványos kimenetre mindkettő darabszámát!

Tervezd meg az állapotgépet állapot- és tevékenységtáblával, utána írd meg a programot! A programra csak akkor jár pont, ha állapotgépes és a leírt állapottáblát valósítja meg.

Megoldás
s z többi
alap →svolt →zvolt -
svolt - sz++, →alap →alap
zvolt zs++, →alap - →alap

Dzs számláló

Írj állapotgépes programot, amely a szabványos bemenetről olvasott szövegben megszámolja a „dzs” betűket! (Hosszú ddzs egynek számít, nem kell külön foglalkozni vele.) A számlálás után írd ki a szabványos kimenetre a darabszámot!

Tervezd meg az állapotgépet állapot- és tevékenységtáblával, utána írd meg a programot! A programra csak akkor jár pont, ha állapotgépes és a leírt állapottáblát valósítja meg.

Megoldás
d z s többi
alap →dvolt - - -
dvolt - →dzvolt →alap →alap
dzvolt →dvolt →alap dzs++, →alap →alap

Üres sorok száma

A feladat a szabványos bemenetről érkező szövegben (fájl vége jelig) megszámolni, hogy hány üres sor van benne. A szöveget a szabványos kimenetre ki is kell írni változatlanul, majd a szöveg után az üres sorok darabszámát. Üres sornak számít az, amiben nincs karakter, de az is, amiben csak szóközök vannak. Készíts állapotgépes modellt állapottábla és tevékenységtábla megadásával, majd valósítsd meg program formájában!

Sztring feldolgozása: különleges karakterek

A feladat a szabványos bemenetről érkező sztring feldolgozása: a szövegben szereplő \n, \t és \" karakterpárokat a megfelelő karakterrel (újsor, tabulátor, idézőjel) helyettesíteni, és úgy írni a szabványos kimenetre. (Egyéb \ és karakter párok nem szerepelnek a sztringben, kezelésük tetszőleges.) Készíts állapotgépes modellt állapottábla és tevékenységtábla megadásával, majd valósítsd meg program formájában! Pl. be:

hello \n    \"világ\"

ki:

hello
    "világ"!

A1llapotge1p

A számítástechnika hőskorában nem lehetett magyar nyelvű billentyűzetet kapni. Magyar nyelvű, ékezetes szövegeket azonban akkor is kellett írni. Az egyik szövegfeldolgozó program úgy oldotta meg a problémát, hogy az adott, ékezet nélküli magánhangzó után tett 1-es, 2-es és 3-as számjegyekkel jelezte a különféle ékezeteket. Az 1-es jelezte a hosszú magánhangzót (pl. á = a1), a 2-es a két pontot (pl. ö = o2), és a 3-as a csak a magyar nyelvben előforduló hosszú ő és ű betű jelölésére szolgált (pl. ő = o3).

Írj állapotgépes programot, amely egy ilyen módon kódolt szöveget átalakít rendes, ékezetes szöveggé!

Gondolkodtató részfeladatok:

  • Oldd meg, hogy hibás bemeneti kombinációkra hibajelzést adjon a program! Pl. az a2 kombináció hibás, mivel az ä betűt jelentené, amely viszont a magyar nyelvben nem használatos.
  • Érdemes minden magánhangzónak külön állapotot létrehozni? Ne felejtsd el, hogy összesen tíz állapotra vonatkozik ez a kérdés, hiszen nem csak az a, e, i, o és u karakterek után jelentenek mást az 1, 2 és 3 számjegyek, hanem az A, E, I, O és U karakterek után is. Lehetne valahogy paraméterezni az állapotokat?

Rövidítések

Írj állapotgépes programot, amely a soronkért beírt tulajdonnevekből rövidítéseket csinál! Írja ez ki minden szó első betűjét. Pl.

Budapesti Muszaki Egyetem
BME
Elektronikus Eszkozok Tanszeke
EET
Megoldás

A tervezés két állapotot ad: azt, amikor várunk a szó első betűjére (mert azt kell kiírni), és azt, amikor egy szó belsejében vagyunk.

szóköz\negyéb
szóra vár--ki: c
→szóban
szóban→szóra várki: \n
→szóra vár
-

Mondat második szava

Tervezz állapotgépes programot, amelyik a szabványos bemeneten olvasott szövegből minden mondat második szavát írja csak ki! Jelenjenek meg ezek a szavak külön sorban!

Megoldás

A tervezést az „új mondat” állapotnál kell kezdeni. Ide kell kerülnie egy bejövő pont, felkiáltójel vagy kérdőjel karakter hatására a gépnek – de az induláskor is. Ettől meg kell különböztetni az „első szó” állapotot, amelybe akkor kerülünk, amikor az első, szó betűjeként értelmezhető karaktert megkapjuk. Innen a „második szóra vár” állapotba egy újabb szóköz (vagy szóelválasztó) hatására kerülünk. Ez még nem a „második szó” állapot, ahol majd ki kell írni a beolvasott betűket (és ahonnan tovább ugrunk egy újabb szóelválasztó hatására), hiszen itt még sok szóelválasztó jöhet (pl. szóköz), ami még nem jelenti a második szó elkezdését. Ha betűt kapunk, az viszont már igen, és az a második szó első betűje kell legyen, ezért ki is írjuk. Azután egy újabb szóelválasztó hatására onnantól „mondat vége” állapotban működik tovább a gép, és már nem figyel semmire, csak várja a következő mondatelválasztó karaktert, amely hatására minden elölről kezdődik.

. ! ?szóköz \n , : ;egyéb
új mondat--→első szó
első szó→új mondat→második szóra vár-
második szóra vár→új mondat-kiír: c
→második szó
második szó→új mondat→mondat vége
kiír: \n
kiír: c
mondat vége→új mondat--

Érdemes a mondatelválasztó és a szóelválasztó karakter felismeréséhez segédfüggvényeket írni.

Alma, alig, akác

Rajzold meg az ^(alma|alig|akác)$ reguláris kifejezéshez tartozó nemdeterminisztikus automatát, és állapotok összevonásával annak determinisztikus párját! A determinisztikus automata alapján írj fel egy reguláris kifejezést, amelyik pontosan erre a három szóra illeszkedik!

Megoldás

^a(l(ma|ig)|kác)$

2. Kommentszűrők és -számlálók

C komment

A C nyelvben /* és */ közé kell tenni a kommenteket. Ezt sok nyelv átvette, pl. a Java is.

Írj programot, amelyik a szabványos bemenetén beolvassa egy C program szövegét, és kiírja a kimenetére ugyanazt a programot kommentek nélkül!

C kommentben komment?

A C nyelvben /* és */ közé kell tenni a kommenteket. A szabvány viszont tiltja az ilyen kommentek egymásba ágyazását. (Tetszőleges mélységben egymásba ágyazott kommenteket nem lehetne állapotgéppel feldolgozni.) Éppen ezért, ha a fordítók kommentben kommentet látnak, figyelmeztető hibajelzést szoktak adni. Írj programot, amelyik hibaüzenetben jelzi, ha a bemenetén ilyen fordul elő!

Multifilter

Írd át az előző programot úgy, hogy ne csak a /* és */ karakterpárokra működjön, hanem tetszőleges karakterpárokra! Pl. a Pascal nyelvben a kommenteket (* és *) karakterekkel is lehetett jelölni. A kezdő- és végpárokat a felhasználó egy konfigurációs fájlban (multifilter.ini) adhassa meg a programnak! A program ellenőrizze, hogy létezik-e a fájl, és ha nem, adjon hibajelzést, majd lépjen ki! (Ha sikerült megnyitnia a fájlt, abban négy karakternek kell lennie; a nyitó kombinációnak, két karakter, és a záró kombinációnak, újabb két karakter. C-hez a fájlban /**/ lenne, Pascalhoz (**).)

C++ komment

A feladat a szabványos bemenetről érkező szövegben (fájl vége jelig) megszámolni, hogy hány C++ komment van benne, és a darabszámot kiírni. A C++ komment két / (per) jellel kezdődik, és a sor végéig tart, pl.:

printf("Hello"); // Üdvözlet

Ha C++ kommenten belül van „//” karakterpár, az nem növeli a kommentek számát. Készíts állapotgépes modellt állapottábla és tevékenységtábla megadásával, majd valósítsd meg program formájában!

C++ komment → C komment

Alakítsd át úgy a fenti kommentszűrődet, hogy a kitörlés helyett tartsa meg a //-es kommenteket, de alakítsa át azokat /*-os formára!

Pl. ha a bemenete ilyen:

#include <stdio.h>

int main(void) {
    printf("Helló világ!\n");   // Üdvözlet
    return 0;
}

Akkor a kimenete legyen ilyen:

#include <stdio.h>

int main(void) {
    printf("Helló világ!\n");   /* Üdvözlet */
    return 0;
}
Megoldás

A megtalált komment elejénél kiír egy /* karaktersorozatot. A komment belsejében minden karaktert kiír (ahogy máskor is). A komment végén, az újsor a karakternél pedig kiírja a bezáró */-ot, és persze az újsort is (hogy a forráskód tördelése ne változzon).

/\negyéb
alap→perki: cki: c
perki: /*
→komment
ki: /, \n
→alap
ki: /, c
→alap
kommentki: cki: */\n
→alap
ki: c

C++ kommentszűrő

A C++ nyelvben a kommentek a // karakterekkel kezdődnek, és a sor végéig tartanak. Ezt a fajta kommentet olyan kényelmesnek találta mindenki, hogy sok más nyelv is átvette.

Írj programot, amelyik a szabványos bemenetén érkező, //-es kommenteket tartalmazó forráskódból kiszűri a kommenteket! Figyelj arra, hogy ettől a program tördelése ne változzon meg: ami eredetileg két sorba volt törve, az a kimeneten is így szerepeljen.

Megoldás
/\negyéb
alap→perki: cki: c
perkommentki: /, \n
→alap
ki: /, c
→alap
komment-ki: \n
→alap
-

Haskell komment

A feladat a szabványos bemenetről érkező Haskell nyelvű programkódban megszámolni, hogy hány komment van benne, és a darabszámot kiírni. A szöveg végét fájl vége jelzi. A Haskell komment két - (mínusz) jellel kezdődik, és a sor végéig tart, pl.:

lesser = filter (< p) xs -- kivalogatja a p-nel kisebbeket

Ha a kommenten belül van „--” karakterpár, az nem növeli a kommentek számát. Készíts állapotgépes modellt állapottábla és tevékenységtábla megadásával, majd valósítsd meg program formájában!