8. Sztringek

8.1. Összetett adattípusok

A könyv korábbi részében megismerkedtünk az int, float, bool és az str típussal, illetve foglalkoztunk a listákkal és az értékpárokkal is. A sztringek, listák és párok jellegi eltérést mutatnak a többi típushoz képest, ezek ugyanis kisebb részekből épülnek fel. Például a sztringek építőelemei egyetlen karaktert tartalmazó sztringek.

A több, kisebb részből összeálló típusokat összetett (adat)típusoknak nevezzük. Az összetett értékeket kezelhetjük egyetlen egységként is, de a részeihez is hozzáférhetünk, attól függően, hogy mi a célunk. Ez a kettősség igen praktikus.

8.2. Sztringek kezelése egy egységként

Az előző fejezetekben láthattuk, hogy minden egyes teknőcpéldány saját attribútumokkal és rá alkalmazható metódusokkal rendelkezik. Beállíthattuk például a teknőcök színét, és írhattunk olyat, hogy Eszter.left(90).

A sztringek is objektumok, akár a teknőcök, tehát minden egyes sztring példánynak vannak saját attribútumai és metódusai.

Az alábbi kódrészletben az upper például egy metódus:

1
2
3
ss = "Helló, Világ!"
tt = ss.upper()
print(tt)

Az upper bármely sztring objektumra meghívva egy új sztring objektumot állít elő, amelyben már minden karakter nagybetűs, tehát a kódrészlet a HELLÓ, VILÁG! üzenetet jeleníti meg. (Az eredeti ss változatlan marad.)

Létezik sok más érdekes függvény is. A lower metódus például a sztring kisbetűs, a capitalize a sztring nagy kezdőbetűs, de egyébként kisbetűs változatát hozza létre, míg a swapcase egy olyan sztring példányt ad vissza, melyben az eredeti sztring kisbetűiből nagybetűk, a nagybetűiből kisbetűk lesznek.

Ha szeretnéd megtudni, milyen metódusok érhetők el, akkor olvasd el a Python dokumentáció string modulról szóló részét, vagy – lustább megoldásként – gépeld be egy PyCharm szkriptbe a következőt:

1
2
ss = "Helló, Világ"
xx = ss.

Amint a pontot kiteszed a PyCharm megnyit egy felugró ablakot, amelyben az ss sztring összes olyan metódusa látszik, amelyet rá alkalmazhatsz (a metódusok neve előtt egy kis «m» áll). Körülbelül 70 van. Hála az égnek, mi csak néhányat fogunk használni!

Sztring metódusok.

A felugró ablakban az is látszik, hogy az egyes metódusok milyen paramétereket várnak. Amennyiben további segítségre van szükséged, akkor a metódus nevén állva nyomd le a Ctrl+Q billentyűkombinációt a függvényhez tartozó leírás megjelenítéséhez. Ez egy jó példa arra, hogy egy fejlesztői eszköz, a PyCharm, hogyan használja fel a modul készítői által nyújtott meta-adatokat, vagyis a dokumentációs sztringeket.

Súgó

8.3. Sztringek kezelése részenként

Az indexelő operátor egyetlen karakterből álló részsztringet jelöl ki egy sztringből. Pythonban az index mindig szögletes zárójelek között áll:

1
2
3
gyumolcs = "banán"
m = gyumolcs[1]
print(m)

A gyumolcs[1] kifejezés a gyumolcs változóban álló sztring 1-es indexű karakterét jelöli ki. Készít egy új sztringet, amely csak a kiválasztott karaktert tartalmazza. Az eredményt az m változóba mentjük.

Az m megjelenítésnél érhet bennünket némi meglepetés:

a

Az informatikusok mindig nullától számolnak! Mivel a "banán" sztring 0. pozícióján a b betű áll, az 1. pozíción az a betűt találjuk.

Ha a nulladik betűt kívánjuk elérni, csak írjunk egy 0-t, vagy bármilyen kifejezést, ami kiértékelve 0-át ad, a szögletes zárójelek közé:

1
2
m = gyumolcs[0]
print(m)

Most már az alábbi kimenetet kapjuk:

b

A zárójelben lévő kifejezést indexnek nevezzük. Az index adja meg, hogy egy rendezett gyűjtemény elemei – jelen esetben a sztring karakterei – közül melyik elemet kívánjuk elérni. Tetszőleges egész kifejezés lehet.

Az indexeket megjeleníthetjük az enumerate függvény segítségével:

1
2
3
gyumolcs = "banán"
lista = list(enumerate(gyumolcs))
print(lista)

Az eredményül kapott lista (index, karakter) értékpárokat tartalmaz:

[(0, 'b'), (1, 'a'), (2, 'n'), (3, 'á'), (4, 'n')]

Az enumerate függvény miatt ne aggódj, a listáknál majd foglalkozunk vele.

Az index operátor egy sztringet ad vissza. Pythonban nincs külön típus a karakterek tárolására, ezek 1 hosszúságú sztringek.

Az előző fejezetekben listákkal is találkoztunk már. Az indexelő operátor segítségével a listák egyes elemeit is elérhetjük. A jelölés ugyanaz, mint a sztringeknél:

1
2
3
4
5
6
7
primek = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
p4 = primek[4]
print(p4)

baratok = ["Misi","Petra","Botond","Jani","Csilla","Peti","Norbi"]
b3 = baratok[3]
print(b3)
A szkript kimenete az alábbi:
11
Jani

8.4. Hossz

A len függvénnyel meghatározható a sztringben álló karakterek száma, amely az alábbi példában 5:

1
2
3
gyumolcs = "banán"
hossz = len(gyumolcs)
print(hossz)

Ha az utolsó betűt szeretnénk elérni, ígéretesnek tűnhet az alábbi kódrészlet:

1
2
sz = len(gyumolcs)
utolso = gyumolcs[sz]       # HIBA!

Nos, ez nem fog működni. Futási hibát okoz (IndexError: string index out of range), ugyanis a "banán" sztring 5. pozícióján nem áll semmilyen karakter. A számozás 0-tól indul, tehát az indexek 0-tól 4-ig vannak számozva. Az utolsó karakter eléréséhez le kell vonnunk 1-et a gyumolcs változóban tárolt szöveg hosszából:

1
2
3
sz = len(gyumolcs)
utolso = gyumolcs[sz-1]
print(utolso)

Egy másik megoldási lehetőség, ha negatív indexet alkalmazunk. A negatív indexek számozása a sztring végétől indul -1-es értékkel. A gyumolcs[-1] az utolsó karaktert, a gyumolcs[-2] az utolsó előttit (hátulról a másodikat) adja meg, és így tovább.

Valószínűleg már kitaláltad, hogy a negatív indexelés a listák esetében is hasonlóan működik.

A könyv további részében nem fogjuk alkalmazni a negatív indexeket. Feltehetően jobban jársz, ha kerülöd a használatát, ugyanis nem sok programozási nyelv enged meg ilyesmit. Az interneten viszont rengeteg olyan Python kód van, ami használja ezt a trükköt, ezért nem árt tudni a létezéséről.

8.5. Bejárás és a for

Igen sok olyan számítási probléma van, ahol a sztring karaktereit egyesével dolgozzuk fel. Általában a sztring elejétől indul a folyamat: vesszük a soron következő karaktert, csinálunk vele valamit, és ezt a két lépést ismételjük a sztring végéig. Az ilyen feldolgozási módot bejárásnak hívjuk.

A bejárást megvalósíthatjuk például while utasítás segítségével:

1
2
3
4
5
i = 0
while i < len(gyumolcs):
    karakter = gyumolcs[i]
    print(karakter)
    i += 1

Ez a ciklus a sztringet járja be, miközben minden egyes karakterét külön-külön sorba megjeleníti. A ciklusfeltétel az i < len(gyumolcs). Amikor az i értéke a sztring hosszával azonos, akkor a feltétel hamis, tehát a ciklus törzs nem hajtódik végre. A legutoljára feldolgozott karakter a len(gyumolcs)-1 pozíción áll, vagyis a sztring utolsó karaktere.

Na de korábban már láttuk, hogy a for ciklus milyen könnyen végig tudja járni egy lista elemeit. Sztringekre is működik:

1
2
for c in gyumolcs:
    print(c)

A c változóhoz minden egyes cikluslépésnél hozzárendelődik a sztring következő karaktere, egészen addig, ameddig el nem fogynak a karakterek. Itt láthatjuk a for ciklus kifejező erejét a while ciklussal történő sztring bejárással szemben.

A következő kódrészlet az összefűzésre ad példát, és megmutatja, hogyan használható a for ciklus egy ábécérendben álló sorozat generálásához. Mindehhez Peyo (Pierre Culliford) híres rajzfilmsorozatának, a Hupikék törpikéknek a szereplőit, Törpapát, Törperőst, Törpicurt, Törpköltőt, Törpmorgót, Törpöltőt és Törpszakállt hívjuk segítségül. Az alábbi ciklus az ő neveiket listázza ki betűrendben:

1
2
3
4
5
elotag = "Törp"
utotagok_listaja = ["erős", "költő", "morgó", "öltő", "papa", "picur", "szakáll" ]

for utotag in utotagok_listaja:
    print(elotag + utotag)

A program kimenete az alábbi:

Törperős
Törpköltő
Törpmorgó
Törpöltő
Törppapa
Törppicur
Törpszakáll

Természetesen ez nem teljesen jó, ugyanis Törpapa és Törpicur neve hibásan szerepel. Majd a fejezet végén szereplő feladatok megoldása során kijavítod.

8.6. Szeletelés

Szeletnek vagy részsztringnek nevezzük a sztring azon részét, melyet annak szeletelésével kaptunk. A szeletelést listákra is alkalmazhatjuk, hogy megkapjuk az elemek egy részlistáját. A könnyebb követhetőség érdekében ezúttal a sorok mellett álló kommentben adjuk meg a kimenetet:

1
2
3
4
5
6
s = "A Karib-tenger kalózai"
print(s[0:1])        # A
print(s[2:14])       # Karib-tenger
print(s[15:22])      # kalózai
baratok = ["Misi","Petra","Botond","Jani","Csilla","Peti","Norbi"]
print(baratok[2:4])  # ['Botond', 'Jani']

Az operátor [n:m] visszaadja a sztring egy részét az n. karakterétől kezdve az m. karakterig, az n. karaktert beleérve, az m.-et azonban nem. Ha az indexeket a karakterek közé képzeled, ahogy azt az ábrán látod, akkor logikusnak fogod találni:

A 'banán' sztring

Képzeld el, hogy ez egy papírdarab. Az [n:m] szeletelés az n. és az m. vonal közti papírdarabot másolja ki. Ha a megadott n és m is a sztringen belül van, akkor az új sztring hossza (m-n) lesz.

Trükkök a szeleteléshez: Ha elhagyjuk az első indexet (a kettőspont előtt), akkor a sztring elejétől induló részletet másolunk ki. Ha elhagyjuk a második indexet, illetve ha a sztring hosszával egyenlő vagy annál nagyobb értéket adunk az m-nek, akkor a szeletelés a sztring végéig tartó részt adja meg. (A szeletelés, szemben az indexelő operátorral, nem ad index out of range hibaüzenetet, ha túlmegyünk a tartományon.) Tehát:

1
2
3
4
5
6
7
gyumolcs = "banán"
gy = gyumolcs[:3]
print(gy)      # ban
gy = gyumolcs[3:]
print(gy)      # án
gy = gyumolcs[3:999]
print(gy)      # án

Mit gondolsz, mi lesz az s[:] és a baratok[4:] eredménye?

8.7. Sztringek összehasonlítása

Lássuk a sztringeken dolgozó összehasonlító operátorokat. Két sztring egyenlőségét az alábbi módon ellenőrizhetjük:

1
2
if szo == "banán":
    print("Nem, nincs banánunk!")

Más összehasonlító operátorok a szavak lexikografikus sorrendbe való rendezésére is alkalmasak:

1
2
3
4
5
6
if szo < "banán":
    print("A szavad, a(z) " + szo + ", a banán elé jön.")
elif szo > "banán":
    print("A szavad, a(z) " + szo + ", a banán után jön.")
else:
    print("Nem, nincs banánunk!")

A lexikografikus sorrend a szótárakban lévő alfabetikus sorrendhez hasonlít, azonban az összes nagybetű a kisbetűk előtt áll. Valahogy így:

A szavad, a(z) Zebra, a banán elé jön.

A probléma kezelésére bevett szokás a sztringek egységes formára való átalakítása, például kisbetűsítése, az összehasonlítás előtt. Nagyobb kihívás lesz annak megoldása, hogy a program rájöjjön, a zebra nem is gyümölcs.

Ha alaposan teszteljük a fenti kódrészletet, más meglepetés is érhet minket:

A szavad, a(z) áfonya, a banán után jön.

A probléma orvosolásához állítsuk be a, hogy milyen nyelvet és milyen karakterkódolást kívánunk használni, majd hasonlítsuk össze a sztringeket egy olyan függvény, az strcoll(s1, s2) segítségével, amely figyelembe veszi ezt a beállítást. A függvény nullát ad eredményül, ha a hasonlítandó sztringek egyformák, -1 értéket ad, ha az s1 paraméternek átadott sztring betűrendben előrébb áll, mint az s2-nek átadott sztring, különben pedig +1 értéket ad. Az előző példánkat átírva, az alábbi kódrészletet kapjuk:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import locale

szo = input("A szavad: ")
locale.setlocale(locale.LC_ALL, "HU_hu.UTF8")  # a nyelv és a kódolás beállítása

k = locale.strcoll(szo, "banán")  # a két sztring összehasonlítása
if k < 0:
    print("A szavad, a(z) " + szo + ", a banán elé jön.")
elif k > 0:
    print("A szavad, a(z) " + szo + ", a banán után jön.")
else:
    print("Nem, nincs banánunk!")

8.8. A sztringek módosíthatatlanok

Ha egy sztring egy karakterét szeretnénk megváltoztatni, kézenfekvőnek tűnhet az indexelő operátort ([]) egy értékadás bal oldalára írni. Valahogy így:

1
2
3
koszontes = "Helló, Világ!"
koszontes[0] = 'J'            # HIBA!
print(koszontes)

Az eredmény a Jelló, Világ! helyett egy futási hiba (TypeError: 'str' object does not support item assignment), amely jelzi számunkra, hogy az str objektumok elemeihez nem rendelhető érték.

A sztringek módosíthatatlanok, vagyis a meglévő sztringet nem változtathatjuk meg. Annyit tehetünk, hogy létrehozzuk a módosítani kívánt sztring egy új változatát:

1
2
3
koszontes = "Helló, Világ!"
uj_koszontes = 'J'+ koszontes[1:]
print(uj_koszontes)

Az itt álló megoldás az új első betűt és a koszontes változóban lévő sztring egy szeletét fűzi össze. Az eredeti sztringre nincs hatással a művelet.

8.9. Az in és a not in operátor

Az in operátorral tartalmazást ellenőrizhetünk. Ha az operátor mindkét operandusa sztring, akkor azt adja meg, hogy az in jobb oldalán álló sztring tartalmazza-e a bal oldalán álló sztringet.

1
2
3
4
5
6
7
8
szerepel_e = "m" in "alma"
print(szerepel_e)          # True
szerepel_e = "i" in "alma"
print(szerepel_e)          # False
szerepel_e = "al" in "alma"
print(szerepel_e)          # True
szerepel_e = "la" in "alma"
print(szerepel_e)          # False

Fontos megjegyezni, hogy egy sztring részsztringjeinek halmazába saját maga és az üres sztring is beletartozik. (Mint ahogy azt is, hogy a programozók mindig szeretik alaposan átgondolni a szélsőséges eseteket!) Az alábbi kifejezések mindegyikének True az értéke:

1
2
3
4
"a" in "a"
"alma" in "alma"
"" in "a"
"" in "alma"

A not in operátor az in operátor logikai ellentétét adja meg, ezért a következő kifejezés is True értékű.

1
"x" not in "alma"

Az in és az összefűzés (+) operátorok alkalmazásával már egy olyan függvényt is el tudunk készíteni, amely az összes magánhangzót eltávolítja egy szövegből:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def maganhangzo_torles(s):
    maganhangzok = "aáeéiíoóöőuúüűAÁEÉIÍOÓÖŐUÚÜŰ"
    massalhangzos_s = ""
    for k in s:
        if k not in maganhangzok:
            massalhangzos_s += k
    return massalhangzos_s

teszt(maganhangzo_torles("informatika") == "nfrmtk")
teszt(maganhangzo_torles("aábeéiífoóöőujúüűpAÁEÉIÍOÓÖŐUÚÜŰs") == "bfjps")

8.10. Egy kereses függvény

Mit csinál az alábbi függvény?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def kereses(szoveg, k):
    """
      Megkeresi a k karaktert a szövegben (szoveg) és visszatér annak indexével.
      A visszatérési érték -1, ha a k karakter nem szerepel a szövegben.
    """
    i = 0
    while i < len(szoveg):
        if szoveg[i] == k:
            return i
        i += 1
    return -1

teszt(kereses("Informatika", "o") == 3)
teszt(kereses("Informatika", "I") == 0)
teszt(kereses("Informatika", "a") == 6)
teszt(kereses("Informatika", "x") == -1)

A kereses függvény bizonyos értelemben az indexelő operátor ellentéte. Míg az indexelő operátorral a sztring egy adott indexén álló karakterét érhetjük el, a kereses függvény egy megadott karakter alapján adja meg, hogy az melyik indexen áll a sztringen belül. Ha a karakter nem található, akkor -1-et ad vissza a függvény.

Láthatunk egy újabb példát a return utasítás cikluson belül való alkalmazására is. Ha a szoveg[i] == k, akkor a függvény azonnal befejezi működését, idő előtt megszakítva a ciklus végrehajtását.

Amennyiben a karakter nem szerepel a sztringben, a program a normális módon lép ki a ciklusból, és -1-et ad vissza.

A fenti programozási minta hasonlóságot mutat a rövidzár kiértékeléssel, hiszen azonnal befejezzük a munkát, amint megismerjük az eredményt, az esetleges hátralévő részek feldolgozása nélkül. Találó név lehetne erre az algoritmusra a Heuréka bejárás, mivel ha ráleltünk a keresett elemre, már kiálthatjuk is: „Heuréka!”. Leggyakrabban azonban teljes keresés néven fogsz találkozni vele.

8.11. Számlálás ciklussal

A következő program az a betűk előfordulásának számát határozza meg egy sztringenben. Ez lesz a második példánk, ahol a Számjegyek számlálása részben ismertetett számlálás algoritmusát használjuk.

1
2
3
4
5
6
7
8
def a_betuk_szama(szoveg):
    darab = 0
    for k in szoveg:
        if k == "a":
            darab += 1
    return darab

teszt(a_betuk_szama("banán") == 1)

8.12. Opcionális paraméterek

A kereses függvény könnyen módosítható úgy, hogy egy karakter második, harmadik, stb. előfordulását is megtalálhassuk egy sztringben. Egészítsük ki a függvény fejlécét egy harmadik paraméterrel, amely a keresés sztringen belüli kezdőpontját határozza meg:

1
2
3
4
5
6
7
8
9
def kereses2(szoveg, k, kezdet):
    i = kezdet
    while i < len(szoveg):
        if szoveg[i] == k:
            return i
        i += 1
    return -1

teszt(kereses2("banán", "n", 2) == 2)

A kereses2("banán", "n", 2) függvényhívás 2-t ad vissza, ugyanis az "n" karakter a 2. pozíción fordul elő először a "banán" sztringben. Mi lenne a kereses2("banán", "n", 3) hívás eredménye? Ha a válaszod 4, akkor valószínűleg sikeresen megértetted a kereses2 működését.

Még jobb, ha a kereses és a kereses2 függvényeket egybeépítjük egy opcionális paramétert alkalmazva:

1
2
3
4
5
6
7
def kereses(szoveg, k, kezdet = 0):
    i = kezdet
    while i < len(szoveg):
        if szoveg[i] == k:
            return i
        i += 1
    return -1

Az opcionális paraméternek a függvény hívója adhat át argumentumot, de nem kötelező megtennie. Ha adott át 3. argumentumot a hívó, akkor az a szokásos módon hozzárendelődik a kereses függvény kezdet paraméteréhez. Máskülönben a kezdet paraméter alapértelmezett értéket kap, jelen esetben 0-át a függvénydefinícióban szereplő, kereses=0 hatására.

Szóval a kereses("banán", "n", 2) hívás esetében a kereses függvény úgy működik, mint a kereses2, a kereses("banán", "n") hívásnál viszont 0 alapértelmezett értéket kap a kezdet paraméter.

Egy újabb opcionális paraméterrel elérhetjük, hogy a keresés az első paraméterben megadott pozícióról induljon, és érjen véget egy második paraméterben megadott pozíció előtt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def kereses(szoveg, k, kezdet = 0, veg = None):
    i = kezdet
    if veg is None:
        veg = len(szoveg)

    while i < veg:
        if szoveg[i] == k:
            return i
        i += 1
    return -1

A veg opcionális paraméter egy érdekes eset. Amennyiben a hívó nem ad meg számára argumentumot, akkor a None rendelődik hozzá, mint alapértelmezett érték. A függvény törzsében a paraméter értéke alapján megállapítjuk, hogy a hívó megadta-e hol érjen véget a keresés. Ha nem adta meg, akkor a veg változó értékét felülírjuk a sztring hosszával, különben az argumentumként kapott pozíciót használjuk a ciklusfelvételben.

A kezdet és a veg paraméterek ebben a függvényben pontosan azzal a jelentéssel bírnak, mint a beépített range függvény start és stop paraméterei.

Néhány teszteset, amelyen a függvénynek át kell mennie:

1
2
3
4
5
6
ss = "Érdekes metódusai vannak a Python sztringeknek."
teszt(kereses(ss, "e") == 3)
teszt(kereses(ss, "e", 5) == 5)
teszt(kereses(ss, "e", 6) == 9)
teszt(kereses(ss, "e", 18, 34) == -1)
teszt(kereses(ss, ".") == len(ss) - 1)

8.13. A beépített find metódus

Most, hogy már túl vagyunk egy hatékony kereső függvény, a kereses megírásának kemény munkáján, elárulhatjuk, hogy a sztringeknek van egy beépített metódusa erre a célra, a find. Mindenre képes, amire a saját függvényünk, sőt még többre is!

1
2
3
4
5
teszt(ss.find("e") == 3)
teszt(ss.find("e", 5) == 5)
teszt(ss.find("e", 6) == 9)
teszt(ss.find("e", 18, 34) == -1)
teszt(ss.find(".") == len(ss) - 1)

A beépített find metódus általánosabb, mint a mi verziónk, ugyanis sztringet is kereshetünk vele egy sztringben, nem csak karaktert:

1
2
3
4
 hol_van = "banán".find("nán")
 print(hol_van)
 hol_van = "papaja".find("pa", 1)
 print(hol_van)

Mindkét esetben 2-es indexet ad vissza a find metódus. (Továbbra is 0-tól számozunk.)

Többnyire a Python által biztosított beépített függvények használatát javasoljuk a saját változataink helyett. Ugyanakkor számos beépített függvény és metódus van, amelyek újírásával nagyszerűen lehet tanulni. A mögöttes megoldások, technikák elsajátításával olyan „építőkockák” kerülnek a kezedbe, amelyek segítenek majd képzett programozóvá válni.

8.14. A split metódus

A split a sztringek egyik leghasznosabb metódusa, ugyanis a több szóból álló sztringeket szavak listájává alakítja át. A szavak közt álló whitespace karaktereket (szóközöket, tabulátorokat, újsor karaktereket) eltávolítja. Ez a függvény lehetővé teszi, hogy egyetlen sztringként olvassunk be egy inputot, és utólag bontsuk szavakra.

1
2
3
ss = "Nos én sose csináltam mondta Alice"
szavak = ss.split()
print(szavak)

A kódrészlet hatására az alábbi lista jelenik meg:

['Nos', 'én', 'sose', 'csináltam', 'mondta', 'Alice']

8.15. A sztringek tisztítása

Gyakran dolgozunk olyan sztringekkel, amelyek különböző írásjeleket, tabulátorokat, vagy újsor karaktert tartalmaznak. Egy későbbi fejezetben tapasztalni is fogjuk ezt, amikor már internetes honlapokról szedjük le, vagy fájlokból olvassuk fel a feldolgozni kívánt szövegeket. Ha azonban olyan programot írunk, ami a szavak gyakoriságát határozza meg, vagy az egyes szavak helyesírását ellenőrzi, akkor előnyösebb megszabadulni ezektől a nemkívánatos karakterektől.

Az alábbiakban mutatunk egy példát arra, hogyan távolíthatók el a különféle írásjelek a sztringekből. A sztringek ugye módosíthatatlanok, ezért nem változtathatjuk meg az eredeti sztringet. Bejárjuk a sztringet, és egy új sztringet hozunk létre a karakterekből az írásjeleket kihagyva:

1
2
3
4
5
6
7
8
irasjelek = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"

def irasjel_eltavolitas(szoveg):
    irasjel_nelkuli = ""
    for karakter in szoveg:
        if karakter not in irasjelek:
            irasjel_nelkuli += karakter
    return irasjel_nelkuli

Az első értékadás kissé kaotikus, könnyen hibához vezethet. Szerencsére a Python string modulja definiál egy sztring konstanst, mely tartalmazza az írásjeleket. A programunk javított változatának elkészítéséhez importáljuk a sztring modult, és használjuk fel az ott megadott definíciót.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import string

def irasjel_eltavolitas(szoveg):
    irasjel_nelkuli = ""
    for karakter in szoveg:
        if karakter not in string.punctuation:
            irasjel_nelkuli += karakter
    return irasjel_nelkuli


teszt(irasjel_eltavolitas('"Nos, én sose csináltam!" - mondta Alice') ==
      "Nos én sose csináltam  mondta Alice")
teszt(irasjel_eltavolitas("Teljesen, de teljesen biztos vagy benne?") ==
      "Teljesen de teljesen biztos vagy benne")

Az előző részben látott split metódus és ennek a függvénynek az egymásba ágyazásával, egy felettébb hatásos kombinációt kapunk. Először eltávolíthatjuk az írásjeleket, majd a split segítségével a szöveget szavak listájára bontjuk, megszabadulva egyúttal az újsor karaktertől és a tabulátoroktól is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
a_tortenetem = """
A pitonok nem méreggel ölnek, hanem kiszorítják a szuszt az áldozatukból.
A prédájuk köré tekerik magukat, minden egyes lélegzeténél egy kicsit
szorosabban, egészen addig, amíg a légzése abba nem marad. Amint megáll
a zsákmány szíve, lenyelik az egészet. A bunda és a tollazat kivételével
az egész állat a kígyó gyomrába lesz temetve. Mit gondolsz, mi történik
a lenyelt bundával, tollakkal, csőrökkel és tojáshéjakkal? A felesleges
'dolgok' távoznak, -- jól gondolod -- kígyó ÜRÜLÉK lesz belőlük!"""

szavak = irasjel_eltavolitas(a_tortenetem).split()
print(szavak)

A kimenet:

['A', 'pitonok', 'nem', ... , 'kígyó', 'ÜRÜLÉK', 'lesz', 'belőlük']

Sok más hasznos sztring metódus létezik, azonban ez a könyv nem szándékozik referenciakönyv lenni. A Python Library Reference viszont az, elérhető a Python honlapján más dokumentációk társaságában.

8.16. A sztring format metódusa

Python 3-ban a legkönnyebb és leghatásosabb módja a sztringek formázásának a format metódus alkalmazása. Nézzük is meg néhány példán keresztül, hogyan működik:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
s1 = "A nevem {0}!".format("Artúr")
print(s1)

nev = "Alice"
kor = 10
s2 = "A nevem {1}, és {0} éves vagyok.".format(kor, nev)
print(s2)

n1 = 4
n2 = 5
s3 = "2**10 = {0} és {1} * {2} = {3:f}".format(2 ** 10, n1, n2, n1 * n2)
print(s3)

A szkript futtatása az alábbi kimenetet eredményezi:

A nevem Artúr!
A nevem Alice, és 10 éves vagyok.
2**10 = 1024 és 4 * 5 = 20.000000

A formázandó sztringbe helyettesítő mezőket ágyazhatunk: ... {0} ... {1} ... {2} ..., stb. A format metódus a mezőket kicserélni az argumentumként átadott értékekre. A helyettesítő mezőben álló szám, az arra a helyre behelyettesítendő argumentum sorszámát adja meg. Ne menj tovább, ameddig a 6-os sort meg nem érted a fenti kódban.

Van tovább is! A helyettesítő mezőket formázó mezőknek is szokás nevezni, utalva arra, hogy mindegyik mező tartalmazhat formátum leírót. A formátum leírókat mindig „:” szimbólum vezeti be, mint a fenti példa 11. sorában. Az argumentumok sztringbe való helyettesítésére vannak hatással. Az alábbiakhoz hasonló formázási lehetőségekkel élhetünk:

  • Balra (<), jobbra (>) vagy középre (^) legyen-e igazítva a mező?
  • Milyen széles mezőt kell lefoglalni az argumentum számára a formázandó sztringen belül? (pl. 10)
  • Történjen-e konverzió? (Eleinte csak float típusú konverziót (f) fogunk alkalmazni, ahogy azt a fenti példa 11. sorában is tettük, esetleg egy egész értéket fogunk hexadecimális alakra hozatni az x-szel).
  • Ha a konverzió típusa float, akkor megadható a megjelenítendő tizedesjegyek száma is. (A .2f megfelelő lehet a pénznemek kiíratásánál, ami általában két tizedesjegyig érdekes. )

Lássunk most néhány szokványos, egyszerű példát, amikben szinte minden benne van, amire szükségünk lehet. Ha netán valami különlegesebb formázásra van igényed, akkor olvasd el a dokumentációt, amely részletekbe menően tárgyal minden lehetőséget.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
n1 = "Paris"
n2 = "Whitney"
n3 = "Hilton"

print("A pi értéke három tizedesjegyig: {0:.3f}".format(3.1415926))
print("123456789 123456789 123456789 123456789 123456789 123456789")
print("|||{0:<12}|||{1:^12}|||{2:>12}|||Születési év: {3}|||"
      .format(n1, n2, n3, 1981))
print("A {0} decimális érték {0:x} hexadecimális értékké konvertálódik."
      .format(123456))

A szkript kimenete:

A pi értéke három tizedesjegyig: 3.142
123456789 123456789 123456789 123456789 123456789 123456789
|||Paris       |||  Whitney   |||      Hilton|||Születési év: 1981|||
A 123456 decimális érték 1e240 hexadecimális értékké konvertálódik.

Több helyettesítő mező is hivatkozhat ugyanarra az argumentum sorszámra, illetve lehetnek olyan argumentumok is, amelyekre egyetlen mező sem hivatkozik:

1
2
3
4
5
6
7
8
9
level = """
Kedves {0} {2}!

{0}, van egy rendkívüli üzleti ajánlatom az Ön számára.
Amennyiben küld 10 millió dollárt a bankszámlámra, megduplázom a pénzét...
"""

print(level.format("Paris", "Whitney", "Hilton"))
print(level.format("Bill", "Henry", "Gates"))

A program két levelet eredményez:

Kedves Paris Hilton!

Paris, van egy rendkívüli üzleti ajánlatom az Ön számára.
Amennyiben küld 10 millió dollárt a bankszámlámra, megduplázom a pénzét...


Kedves Bill Gates!

Bill, van egy rendkívüli üzleti ajánlatom az Ön számára.
Amennyiben küld 10 millió dollárt a bankszámlámra, megduplázom a pénzét...

Ha egy helyettesítő mező nem létező argumentum sorszámot tartalmaz, akkor a várakozásoknak megfelelően, indexhibát kapunk:

1
2
3
4
"helló {3}".format("Dávid")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
IndexError: tuple index out of range

A következő példa a sztring formázás igazi értelmét mutatja meg. Először próbáljunk egy táblázatot sztring formázás nélkül kiíratni:

1
2
3
4
print("i\ti**2\ti**3\ti**5\ti**10\ti**20")
for i in range(1, 11):
    print(i, "\t", i**2, "\t", i**3, "\t", i**5, "\t",
                                            i**10, "\t", i**20, sep='')

A program az [1; 10] tartományba eső egész számok különböző hatványait jeleníti meg. (A kimenet megadásánál feltételeztük, hogy a tabulátor szélessége 8-ra van állítva. PyCharmon belül az alapértelmezett tabulátorszélesség 4 szóköznyi, ezért még ennél is rosszabb kimenetre számíthatsz. A print utasításban a sep='' kifejezéssel érhető el, hogy ne kerüljön szóköz a kimenetben vesszővel elválasztott argumentumok közé.)

A program e változatában tabulátor karakterekkel (\t) rendeztük oszlopokba az értékeket, de a formázás elcsúszik azoknál a táblázatbeli értékeknél, amelyek több számjegyből állnak, mint amennyi a tabulátor szélessége:

i       i**2    i**3    i**5    i**10   i**20
1       1       1       1       1       1
2       4       8       32      1024    1048576
3       9       27      243     59049   3486784401
4       16      64      1024    1048576         1099511627776
5       25      125     3125    9765625         95367431640625
6       36      216     7776    60466176        3656158440062976
7       49      343     16807   282475249       79792266297612001
8       64      512     32768   1073741824      1152921504606846976
9       81      729     59049   3486784401      12157665459056928801
10      100     1000    100000  10000000000     100000000000000000000

Egy lehetséges megoldás a tabulátor szélességének átállítása, de az első oszlop már most is szélesebb a kelleténél. A legjobb megoldás a problémára, ha oszloponként állítjuk be a megfelelő szélességet. Valószínűleg nem ér meglepetésként, hogy a sztring formázással szebb eredményt érhetünk el. Még jobbra is igazíthatjuk a mezőket:

1
2
3
4
5
elrendezes = "{0:>4}{1:>6}{2:>6}{3:>8}{4:>13}{5:>24}"

print(elrendezes.format("i", "i**2", "i**3", "i**5", "i**10", "i**20"))
for i in range(1, 11):
    print(elrendezes.format(i, i ** 2, i ** 3, i ** 5, i ** 10, i ** 20))

A futtatás után az alábbi, jóval tetszetősebb kimenet jelenik meg:

 i  i**2  i**3    i**5        i**10                   i**20
 1     1     1       1            1                       1
 2     4     8      32         1024                 1048576
 3     9    27     243        59049              3486784401
 4    16    64    1024      1048576           1099511627776
 5    25   125    3125      9765625          95367431640625
 6    36   216    7776     60466176        3656158440062976
 7    49   343   16807    282475249       79792266297612001
 8    64   512   32768   1073741824     1152921504606846976
 9    81   729   59049   3486784401    12157665459056928801
10   100  1000  100000  10000000000   100000000000000000000

8.17. Összefoglalás

Ebben a fejezetben nagyon sok új gondolat jött elő. Az alábbi összefoglaló segíthet felidézni a tanultakat. (A fejezet címének megfelelően, most a sztringekre koncentrálunk.)

indexelés ([])
Egy sztring adott pozícióján álló karakter elérésére használható. Az indexek számozása 0-tól indul. Például "Ennek"[4] az eredménye "k".
A len függvény
Egy sztring hosszát, vagyis a benne szereplő karakterek számát állapíthatjuk meg vele. Például a len("boldog") eredménye 6.
bejárás for ciklussal (for)

Egy sztring bejárása azt jelenti, hogy minden egyes karakterét pontosan egyszer érintjük. Például a

for k in "Példa":
    ...

ciklus végrehajtása alatt a törzs 5 alkalommal fut le. A k változó minden egyes alkalommal más-más értéket vesz fel.

szeletelés ([:])
A sztringek valamely részének, egy részsztringnek az elérésére szolgál. Például: 'papaja tejszínnel'[0:2] eredménye pa (a 'papaja tejszínnel'[2:4] eredménye is az).
sztringek hasonlítása (>, <, >=, <=, ==, !=)
A 6 megszokott hasonlító operátor sztringekre is működik, a lexikografikus sorrendnek megfelelően. Példák: Az "alma" < "banán" eredménye igaz (True). A "Zebra" < "Alma" eredménye hamis (False). A "Zebra" <= "kulonos" eredménye is True, ugyanis a lexikografikus sorrend alapján minden nagybetű a kisbetűk előtt áll.
Az in és a not in operátor (in, not in)
Az in operátor tartalmazás ellenőrzésére szolgál. Sztringekre alkalmazva megadja, hogy egy sztring szerepel-e egy másik sztringben. Például a "sajt" in "kisajtolom belőle" kifejezés értéke igaz, míg az "ementáli" in "kisajtolom belőle" hamis.

8.18. Szójegyzék

alapértelmezett érték (default value)
Az az érték, amit az opcionális paraméter megkap, ha a függvény hívója nem adja meg a hozzá tartozó argumentumot.
bejárás (traverse)
Egy kollekció elemein való végighaladás, miközben minden elemre hasonló műveletet hajtunk végre. A bejárás során minden elemet pontosan egyszer érintünk.
dokumentációs sztring (docstring)
Egy, a függvény első sorában, vagy a modulok definíciójában (és ahogy később látni fogjuk az osztályok és metódusok definíciójában) álló sztring konstans. Kényelmes megoldást nyújtanak a kód és a dokumentáció összekapcsolására. A dokumentációs sztringeket különböző programozási eszközök is használják interaktív súgó szolgáltatásához.
index
Egy változó vagy egy konstans érték, amely egy rendezett sorozat egy elemét jelöli ki, például egy sztring valamely karakterét, vagy egy lista valamely elemét.
minősítés (dot notation)
A pont (.) a minősítés operátora. Egy objektum attribútumait és metódusait érhetjük el vele.
módosíthatatlan érték (immutable data value)
Olyan érték, amely nem változtatható meg. A módosíthatatlan összetett adatoknál, az elemek vagy részek (pl. részsztring) felülírására irányuló kísérlet futási hibát eredményez.
módosítható érték (mutable data value)
Olyan érték, amely módosítása lehetséges. Minden módosítható adat összetett típusú. A listák és a szótárak megváltoztathatóak, a sztringek és a rendezett n-esek (tuples) nem.
opcionális paraméter (optional parameter)
Olyan, a függvény fejlécében szereplő paraméter, amelyhez egy kezdőérték tartozik. Ha a függvény hívója nem ad át a paraméternek argumentumot, akkor az alapértelmezett érték rendelődik a paraméterhez.
összetett adattípus (compound data type)
Olyan típus, amely több komponensből épül fel. A komponensek maguk is típusok. Az összetett típusú értékeket összetett értékeknek nevezzük.
rövidzár-kiértékelés (short-circuit evaluation)
Egy olyan kifejezés kiértékelési módszer, amely csak addig értékeli ki a kifejezést, ameddig az eredmény el nem dől. A rövidzár szóval az olyan programozói stílust is jellemezhetjük, amely megakadályozza az eredmény megismerése utáni felesleges munkavégzést. Például a kereses függvény azonnal visszaadta az eredményt a hívónak, ahogy a keresett karaktert megtaláltuk, nem járta be a sztring még hátra lévő részét.
szelet (slice)
A sztring egy adott indextartománnyal meghatározott részletét szeletnek nevezzük. Általánosabban fogalmazva, a szelet egy sorozat olyan részsorozata, amelyet a szeletelő operátor alkalmazásával kaphatunk (sequence[start:stop]).
whitespace
Minden olyan karakter, amely arrébb viszi a kurzort anélkül, hogy látható karakter jelenne meg. A string.whitespace konstans tartalmazza az összes white-space karaktert.

8.19. Feladatok

Javasoljuk, hogy egy fájlban készítsd el az alábbi feladatokat, az előző feladatokban látott tesztelő függvényeket is bemásolva a fájlba.

  1. Milyen eredményt adnak az alábbi kifejezések? (Ellenőrizd a válaszaid a print függvény segítségével.)

    "Python"[1]
    "A sztringek karaktersorozatok."[5]
    len("csodálatos")
    "Rejtély"[:4]
    "k" in "Körte"
    "barack" in "sárgabarack"
    "körte" not in "Ananász"
    "barack" > "sárgabarack"
    "ananász" < "Barack"
    
  2. Javítsd ki úgy az alábbi programot, hogy Törpapa és Törpicur neve is helyesen jelenjenek meg:

    1
    2
    3
    4
    5
    elotag = "Törp"
    utotagok_listaja = [erős", "költő", "morgó", "öltő", "papa", "picur", "szakáll"]
    
    for utotag in utotagok_listaja:
        print(elotag + utotag)
    
  3. Ágyazd be az alábbi kódrészletet egy karakter_szamlalas nevű függvénybe, majd általánosítsd úgy, hogy a sztringet és a számlálandó karaktert is paraméterként várja. A függvény adja vissza a karakter sztringbeli előfordulásainak számát, ne írassa ki. Az érték megjelenítése a függvény hívójának feladata.

    1
    2
    3
    4
    5
    6
    gyumolcs = "banán"
    darab = 0
    for karakter in gyumolcs:
        if karakter == "a":
            darab += 1
    print(darab)
    
  4. Most írd át úgy a karakter_szamlalas függvényt, hogy a sztring bejárása helyett a beépített find metódusát hívja meg újra és újra. A második paraméternek átadott értékkel biztosíthatod, hogy a metódus mindig új előfordulását találja meg a számlálandó karakternek.

  5. Adj értékül egy bekezdést a kedvenc szövegedből – egy beszédből, egy süteményes receptkönyvből, vagy egy inspiráló versből, stb. – egy változónak. A szöveget tripla idézőjelek közé zárd.

    Írj egy függvényt, amely eltávolítja az összes írásjelet a sztringből, és a szöveget szavak listájára bontja. Számold meg, hány olyan szó van a szövegben, melyben szerepel az „e” betű. Jeleníts meg egy alábbihoz hasonló elemzést a szövegedről:

    A szövegben 243 szó áll, melyből 109 (44.8%) tartalmaz "e" betűt.
    
  6. Jeleníts meg egy ilyen szorzótáblát:

            1   2   3   4   5   6   7   8   9  10  11  12
      :--------------------------------------------------
     1:     1   2   3   4   5   6   7   8   9  10  11  12
     2:     2   4   6   8  10  12  14  16  18  20  22  24
     3:     3   6   9  12  15  18  21  24  27  30  33  36
     4:     4   8  12  16  20  24  28  32  36  40  44  48
     5:     5  10  15  20  25  30  35  40  45  50  55  60
     6:     6  12  18  24  30  36  42  48  54  60  66  72
     7:     7  14  21  28  35  42  49  56  63  70  77  84
     8:     8  16  24  32  40  48  56  64  72  80  88  96
     9:     9  18  27  36  45  54  63  72  81  90  99 108
    10:    10  20  30  40  50  60  70  80  90 100 110 120
    11:    11  22  33  44  55  66  77  88  99 110 121 132
    12:    12  24  36  48  60  72  84  96 108 120 132 144
    
  7. Írj egy függvényt, amely meghatározza egy paraméterként kapott sztring fordítottját. A függvénynek át kell mennie ezeken a teszteken:

    1
    2
    3
    4
    teszt(sztring_forditas("boldog") == "godlob")
    teszt(sztring_forditas("Python") == "nohtyP")
    teszt(sztring_forditas("") == "")
    teszt(sztring_forditas("a") == "a")
    
  8. Írj egy függvényt, amely összefűzi argumentumát annak tükörképével:

    1
    2
    3
    4
    teszt(tukor("jo") == "jooj")
    teszt(tukor("Python") == "PythonnohtyP")
    teszt(tukor("") == "")
    teszt(tukor("a") == "aa")
    
  9. Írj függvényt, amely eltávolítja egy karakter összes előfordulását egy sztringből. A függvény a karaktert és a sztringet is argumentumként várja.

    1
    2
    3
    4
    5
    6
    teszt(betu_eltuntetes("a", "alma") == "lm")
    teszt(betu_eltuntetes("a", "banán") == "bnán")
    teszt(betu_eltuntetes("z", "banán") == "banán")
    teszt(betu_eltuntetes("e", "Kerepes") == "Krps")
    teszt(betu_eltuntetes("b", "") == "")
    teszt(betu_eltuntetes("b", "c") == "c")
    
  10. Írj függvényt, mely képes a palindromok felismerésére. (Segítség: a korábban megírt sztring_forditas függvény felhasználása megkönnyíti a dolgod!):

    1
    2
    3
    4
    5
    6
    7
    teszt(palindrom_e("abba"))
    teszt(not palindrom_e("abab"))
    teszt(palindrom_e("teret"))
    teszt(not palindrom_e("banán"))
    teszt(palindrom_e("mesék késem"))
    teszt(palindrom_e("a"))
    # teszt(palindrom_e(""))    # Egy üres sztring palindrom-e?
    
  11. Írj egy függvényt, amely meghatározza, hányszor szerepel egy sztringben egy másik sztring:

    1
    2
    3
    4
    5
    6
    teszt(szamlalas("gö", "görögös") == 2)
    teszt(szamlalas("pa", "papaja") == 2)
    teszt(szamlalas("apa", "papaja") == 1)
    teszt(szamlalas("papa", "papaja") == 1)
    teszt(szamlalas("apap", "papaja") == 0)
    teszt(szamlalas("aaa", "aaaaaa") == 4)
    
  12. Írj függvényt, amely eltávolítja egy sztringből egy másik sztring első előfordulását:

    1
    2
    3
    4
    5
    teszt(torles("alma", "almafa") == "fa")
    teszt(torles("an", "banán") == "bán")
    teszt(torles("pa", "papaja") == "paja")
    teszt(torles("pa", "Papaja") == "Paja")
    teszt(torles("alma", "kerékpár") == "kerékpár")
    
  13. Írj függvényt, amely eltávolítja egy sztringből egy másik sztring minden előfordulását. (A törlés hatására új előfordulások is keletkezhetnek. Rád bízzuk, hogy ezeket eltűnteted-e.):

    1
    2
    3
    4
    5
    6
    teszt(alapos_torles("an", "banán") == "bán")
    teszt(alapos_torles("pa", "papaja") == "ja")
    teszt(alapos_torles("pa", "Papaja") == "Paja")
    teszt(alapos_torles("alma", "kerékpár") == "kerékpár")
    # A megoldástól függően: "pa" vagy ""
    # teszt(alapos_torles("pa", "ppapaa" ) == "")