14. hét: állapotgépek
Czirkos Zoltán · 2024.11.23.
Állapotgépekkel és reguláris kifejezésekkel kapcsolatos laborfeladatok.
Felkészülés a laborra:
- Az állapotgépekről szóló előadás megértése.
- A fájlkezelés áttekintése.
- A sztringekről, karakterkódokról tanultak átolvasása.
Írj programot, amely a sys
modul sys.stdin.read(1)
függvényhívását használva karakterenként olvas be egy szöveget, majd minden beírt karakternek a karakterkódját
kiírja a kimenetére! Ha pedig elfogyott a bemenet, akkor írja ki, hogy „bemenet vége”.
Figyeld meg a program működését:
- Amíg nem nyomsz entert egy beírt sorra, nem ír ki semmit.
- Utána viszont egyszerre a teljes sor karakterkódját. Miért van ez így?
- Hogy lépsz ki a programból? Nem(!!!) Ctrl–C-vel! Hogy adsz neki fájl vége jelet?
- Minek a karakterkódja a 10?
Ilyesmi kell legyen az eredmény:
hello 104 101 108 108 111 10 Bemenet vége.
Megoldás
import sys
while True:
c = sys.stdin.read(1)
if c == "": break
print(ord(c))
print("Bemenet vége.")
Alább az előadás állapotgépes példakódját látod, az ly-számlálót.
import sys
def main():
ALAP = 1
L_VOLT = 2
LL_VOLT = 3
szaml = 0
allapot = ALAP
while True:
c = sys.stdin.read(1)
if c == "":
break
if allapot == ALAP: # szöveg kezdete
if c == "l":
allapot = L_VOLT
elif allapot == L_VOLT: # már volt egy l
if c == "l":
allapot = LL_VOLT
elif c == "y":
szaml += 1
allapot = ALAP
else:
allapot = ALAP
elif allapot == LL_VOLT: # két l volt
if c == "l":
pass
elif c == "y":
szaml += 2
allapot = ALAP
else:
allapot = ALAP
print(szaml, "darab ly volt.")
main()
Rajzold meg a forráskód alapján állapotátmeneti és tevékenységeket tartalmazó táblázatát, vagy választásod szerint az állapotátmeneti gráfot!
Megoldás
l | y | egyéb | |
---|---|---|---|
alap | →l_volt | - | - |
l_volt | →ll_volt | sz += 1, →alap | →alap |
ll_volt | - | sz += 2, →alap | →alap |
Indulj ki az előző feladat kódjából!
Rajzolj egy új táblázatot, amelyben teljes egészében módosítod a tevékenységeket. Az új program feladata nem az
ly
-ok számlálása, hanem egy „hejesírásreform” végrehajtása. Ennek a beolvasott szöveget majdnem változatlanul
kell kiírnia a kimenetre – azzal a különbséggel, hogy az ly
-ok helyett j
-t, a dupla
lly
-ok helyett jj
-t kell kiírnia. Pl. lyuk→juk
, gally→gajj
, viszont
majom→majom
marad, és a kulcs
, illetve a hallgat
szavak is változatlanok maradnak. (Ezek a
példák fontos állapotátmeneteket és tevékenységeket tesztelnek.)
Megoldás
l | y | egyéb | |
---|---|---|---|
alap | →l_volt | ki: c | ki: c |
l_volt | →ll_volt | ki: "j" →alap | ki: "l", c →alap |
ll_volt | ki: "l" | ki: "jj" →alap | ki: "ll", c →alap |
A kiírásokat itt jól meg kell gondolni. Alapállapotban mindent kiírunk, kivétel az l
betűt, mert az lehet egy
későbbi ly
része. l_volt
állapotban bejövő y
esetén kiírjuk a j
-t; viszont
bejövő egyéb karakter esetén az előző l
-t is ki kell írni, és a mostanit is (ilyen szó: kulcs). ll_volt
esetén pedig, ha bármi más jön, akkor az előző ll
-t is ki kell írni (ilyen szó: hallgat).
A szövegfájloknál bevett szokás az, hogy a fájl legutolsó karaktere mindig egy újsor (\n) karakter. Ezt azonban sajnos nem mindenhol tartják be (és nem minden szövegszerkesztő tesz így).
Ha esetleg kap a fenti program egy olyan bemenetet, ahol a szöveg 'l'
betűre végződik
(tehát nincs újsor, de még mondat vége jel sincs a bemenet végén), akkor hibázik; a kimeneten nem jelenik
majd meg ez a betű.
Emlékezz vissza, mit tanultál az előadáson a programok parancssori futtatásáról, továbbá a fájlból és fájlba átirányításról!
Parancssor gyorstalpaló
A Start menü Futtatás… parancsát választva indítsd el a cmd.exe
programot! (Windows 10 esetén:
a Start gombra jobb klikk, és Futtatás, vagy Windows + R.) A továbbiakban a
megjelenő konzolablakban kell dolgozni. A föl-le billentyűkkel kiválaszthatóak a korábban beírt
parancsok, így nem kell egy dolgot többször begépelni.
Egy program indításához csak be kell írni a nevét. Pl.
notepad.exe
A legtöbb konzolos alkalmazás, de gyakran az ablakokat használó programok is, kaphatnak paramétereket. Próbaképp írd be az alábbi sort. Mit tapasztalsz?
notepad szoveg.txt
A mappát (folder) a parancssori parancsok a directory szóból származtatják (a mappák másik neve, magyarul könyvtár). A mappa tartalmának listázása:
C:\Users\111111\> dir
Mappát váltani a chdir
paranccsal, vagy ennek rövidebb változatával, a
cd
-vel lehet. Lépj egy szinttel feljebb:
C:\Users\111111\> cd ..
Indíts egy parancssort, és futtasd le abból a helyesírásreform programodat! Ehhez operációs rendszertől függően a program nevét
kell megadnod, vagy elé kell írnod azt, hogy python3
, esetleg verziótól függően csak annyit, hogy python
(próbáld ki, a te környezetedben melyik működik). Teszteld újra a programod pl. a lyuk és gally szavakkal, utána lépj ki belőle
fájl vége jellel!
Végezd el a fájlból és fájlba átirányítást is! Erre is mutat példát a hivatkozott előadásrészlet. Hozz létre ehhez a jegyzettömbbel egy „ómagyar.txt” nevű fájlt, benne ly-okat tartalmazó szöveggel. Dolgoztasd ezt fel a programoddal, és irányítsd át a kimenetét az „újmagyar.txt” nevű fájlba!
Megoldás
A lényeg:
python3 hejesirasreform.py <ómagyar.txt >újmagyar.txt
Írj programot, amely:
- Kér a felhasználótól egy reguláris kifejezést.
- Aztán beolvassa a szavak.txt fájlt... (Ezt mentsd le a gépedre!)
- ... és csak azokat a sorait írja ki, amire illeszkedett a megadott kifejezés.
Például:
Kérem a regexet: ^..vé$ kávé kővé tűvé
Ne feledd, a szavak beolvasásához szükség lehet a fájl kódolásának megadására: encoding="utf-8"
paraméter
az open()
függvény számára.
Adj meg reguláris kifejezéseket, amelyekkel kilistázhatod az alábbi szavakat:
- Amelyekben van vicc (pl. vicces, de kaviccsal is)
- Almával kezdődnek (pl. almaecet, de simán alma is)
- Úgy végződnek, hogy hely (pl. táborhely, zabpehely)
- Négy betűsek, és mindkét középső betűjük n (pl. enni).
- Hat betűsek, fru-val kezdődnek (pl. fruska).
- Hosszú ó-val kezdődő és végződő szavak (pl. óceánjáró).
- Két hosszú ssz szerepel bennük (pl. összevisszaság).
- Szerepel bennük kétszer ugyanaz a négybetűs részlet (pl. tisztiszolga, rendszerszerű)
- Hat betűből állnak, kétszer ugyanaz (pl. bonbon)
- Hatbetűs tükörszavak (pl. lappal)
- Hétbetűs tükörszavak (pl. találat)
Megoldás
import re
regex = input("Kérem a regexet: ")
with open("szavak.txt", encoding="utf-8") as f:
for s in f:
s = s.rstrip()
if re.search(regex, s):
print(s)
- Vicc:
vicc
- Alma:
^alma
- Hely:
hely$
- Enni:
^.nn.$
- Fruska:
^fru...$
- Óceánjáró:
^ó.*ó$
- Összevisszaság:
ssz.*ssz
- Tisztiszolga:
(....)\1
- Bonbon:
^(...)\1$
- Lappal:
^(.)(.)(.)\3\2\1$
- Találat:
^(.)(.)(.).\3\2\1$
Adott az alábbi három lehetséges formátum, amelyben időpontokat adhatunk meg:
23:17:06
– óra, perc, másodperc, mindegyik két számjeggyel;15h 09m 53s
– itt is óra, perc, másodperc, mindegyik két számjeggyel;10:15 AM
– itt az óra és a perc két-két számjeggyel. Ez a formátum 12 órás;12:00 AM
= éjfél,08:00 AM
= reggel 8,12:00 PM
= dél,05:00 PM
= a délután 5 óra, azaz 17 óra.
Adj meg reguláris kifejezéseket a három formátumhoz! Írj programot, amelyik folyamatosan sorokat olvas be a bemenetről, és megmondja, hogy az első, a második, vagy a harmadik formátumban van megadva az időpont! Ha esetleg egyikben sem (hibás a bemenet), akkor írd ki azt!
Kérem az időpontot: 12:34:45 Első formátum Kérem az időpontot: 05:34 PM Harmadik formátum Kérem az időpontot: 05:34 PMMMM Hibás
Megoldás
import re
while True:
sor = input("Kérem az időpontot: ")
if sor == "":
break
if re.match(r"^\d{2}:\d{2}:\d{2}$", sor):
print("Első formátum")
elif re.match(r"^\d{2}h \d{2}m \d{2}s$", sor):
print("Második formátum")
elif re.match(r"^\d{2}:\d{2} [AP]M$", sor):
print("Harmadik formátum")
else:
print("Hibás")
Módosítsd az előző feladatban megírt reguláris kifejezéseidet úgy, hogy az egyes időpont formátumok esetén az időpontok értelmezéséhez szükséges adatokat egy zárójelezett blokk segítségével kigyűjtöd!
- Az első két formátumban: óra, perc, másodperc számok.
- A harmadik formátumban: óra, perc és az A vagy a P betű.
Írd ki ezeket a kimenetre!
Végül pedig definiálj egy időpont osztályt (óra, perc, másodperc) konstruktorral, és írj függvényt, amelynek paramétere a fenti három formátumok valamelyikékben adott időpont, visszatérési értéke pedig egy időpont objektum!
Fejleszd tovább a labor eleji „hejesírásreform” programot! Tanítsd meg az állapotgépednek, hogy kezelje helyesen
a mondatot kezdő, nagybetűs L
karaktert! Rajzold meg az új állapotátmeneti táblázatot!
Hány új állapot kell ehhez? Működik helyesen a programod, ha azt írod bemenetként, Levél
?
Vajon kell-e számolnod azzal, hogy mondat elejére két j
-t kell írnod?
Írj állapotgépes programot, amely a beírt, csupa kisbetűkből álló szöveget úgy javítja ki, hogy minden mondat elején álló első betűt nagybetűre cseréli!
Megoldás
Mondat végét jelző írásjel után a következő betű nagybetű, de csak akkor, ha szóköz is jött. Figyelni kell, hogy az utána lévő szóköztől nem váltunk kisbetűs módra még! A gép alapállapota a nagybetűsítés, hiszen a bejövő szöveg legelső karaktere biztosan mondat elején van.
. ! ? | szóköz, \n | egyéb | |
---|---|---|---|
nagybetű | ki: c | ki: c | ki: c.upper() →kisbetű |
kisbetű | ki: c →mondatvége? | ki: c | ki: c |
mondatvége? | ki: c | ki: c →nagybetű | ki: c →kisbetű |
Ha a laborfeladatokkal elkészültél, dolgozz a példatárban lévő feladatokon, a szorgalmi feladatokon, a minta vizsgán, vagy a házi feladatodon.
Informatikusok próbálják lekódolni az Algoritmusok és gráfok tárgyon tanult algoritmusokat. Ezzel két legyet lehet ütni egy csapásra, mert két tantárgyat is gyakoroltok egyszerre.