Néha előfordul, hogy egy szöveget úgy kell megjeleníteni, hogy a sorhossz, vagyis az egy sorban kiírható karakterek maximális száma előre meghatározott. Ilyenkor a szöveget a szóelválasztó karaktereket figyelembe véve több sorba kell tördelni. A sortörésnél arra kell figyelni, hogy az csak egész szó végén történjen, valamint arra, hogy a szóhatároló karakter vagy karakterlánc a sorok végén feleslegesen ne jelenjen meg.
Egy szöveg több sorba való tördelését végző wrap_text nevű függvény egy lehetséges megvalósítása a következő:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
from typing import Iterable def wrap_text(text: str, max_line_length: int, word_separator=' ') -> list[str]: """A megadott szöveget sorokba tördeli úgy, hogy sortörés csak szóvégződés után lehet, és a megadott, karakterekben mért sorhosszt a sorokba kerülő szövegrészek karakterszáma nem haladja meg. A sorok végén a szóhatároló karakterlánc nem jelenik meg. """ # 1. A text tartalmát a szóhatároló karakterláncoknál feldaraboljuk és a részeket egy listában tároljuk el. # 2. Ha a lista nem üres, kivesszük az első elemét. # 3. Ha van még következő elem, vagyis a lista nem üres, akkor a már kivett elem végéhez hozzáfűzzük a szóhatároló karakterláncot. # 4. Ha az így kapott karaktersor kummulált hossza kisebb, mint a hosszkorlát, akkor # - a karaktersort az aktuális sorhoz adjuk, majd # - folytatjuk a 2. lépéstől. # 5. Egyébként - azaz ha a kummulált hossz nagyobb vagy egyenlő, mint a hosszkorlát - akkor # - az aktuális sort felvesszük a sorokat tároló listába, # - az aktuálisan kivett karakterlánc pedig egy új sor nyitó eleme lesz. # - folytatjuk a 2. lépéstől. # 6. Ha a tördelendő szavakat tartalmazó lista kiürül, akkor a sorokat tároló listával térünk vissza. charscount = 0 lines: list[str] = [] current_line: str = '' words: list = text.split(word_separator) while words: word = words.pop(0) if words: word += word_separator charscount += len(word) if charscount <= max_line_length: current_line += word else: lines.append(current_line[:-len(word_separator)]) current_line = word charscount = len(word) lines.append(current_line) return lines |
A függvény első argumentuma a tördelendő szöveg. A második argumentummal határozható meg a maximális sorhossz karakterszámban mérve. A harmadik argumentummal adható meg, hogy az adott szövegben mi tekintendő szóhatároló karakterláncnak. A függvény egy olyan listával tér vissza, amelynek elemei az egyes sorokba kerülő karakterláncok. Ebből következik, hogy e lista elemszáma megadja, hogy az eredeti szöveg hány sorba lett tördelve. A függvény logikája nem túl bonyolult, és a részletes kommentből követhető. Csupán annak megvalósítása igényel némi átgondolást, hogy a szóelválasztó karakterlánc a sorok végén ne jelenjen meg.
A tesztelést egy külön függvény segítségével végezzük, amelynek definíciója ez:
|
1 2 3 4 5 6 7 8 9 10 11 |
def wrap_text_test(text: str, max_line_widths: Iterable, word_separator=' '): print(f'A tördelendő szöveg: "{text}"') for max_line_width in max_line_widths: z = wrap_text(text, max_line_width, word_separator) print(f'\nMaximális sorhossz: {max_line_width}') print(z) print('Az egyes sorok hossza:', *[len(line) for line in z]) print('-' * max_line_width) print(*z, sep='\n') |
Ebben először kiírjuk a tördelendő szöveget és a maximális sorhosszt, amit vizuálisan is megjelenítünk szaggatott vonallal, amelynek hossza mutatja a sorhosszkorlátot. Utána kiírjuk a wrap_text függvény visszatérési értékét jelentő listát, amiből láthatjuk a sorok pontos tartalmát, pl. azt, hogy hol van szóhatároló szóköz és hol nincs. Ezt követően azt is kiírjuk, hogy az egyes sorok milyen hosszúak, amiből ellenőrizhető, hogy egyik sem lépi túl a korlátot. Végül az egyes sorokat egymás alatt megjelenítjük.
A teszteket és eredményeiket alább láthatjuk:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# TESZT1: A szóhatároló karakterlánc egy szóköz text = 'Aki nem lép egyszerre, nem kap rétest estére. Mert a rétes nagyon jó, katonának az való.' wrap_text_test(text, (25, 35, 50)) # Eredmények: # A tördelendő szöveg: "Aki nem lép egyszerre, nem kap rétest estére. Mert a rétes nagyon jó, katonának az való." # # Maximális sorhossz: 25 # ['Aki nem lép egyszerre,', 'nem kap rétest estére.', 'Mert a rétes nagyon jó,', 'katonának az való.'] # Az egyes sorok hossza: 22 22 23 18 # ------------------------- # Aki nem lép egyszerre, # nem kap rétest estére. # Mert a rétes nagyon jó, # katonának az való. # # Maximális sorhossz: 35 # ['Aki nem lép egyszerre, nem kap', 'rétest estére. Mert a rétes nagyon', 'jó, katonának az való.'] # Az egyes sorok hossza: 30 34 22 # ----------------------------------- # Aki nem lép egyszerre, nem kap # rétest estére. Mert a rétes nagyon # jó, katonának az való. # # Maximális sorhossz: 50 # ['Aki nem lép egyszerre, nem kap rétest estére.', 'Mert a rétes nagyon jó, katonának az való.'] # Az egyes sorok hossza: 45 42 # -------------------------------------------------- # Aki nem lép egyszerre, nem kap rétest estére. # Mert a rétes nagyon jó, katonának az való. # TESZT2: A szóhatároló karakterlánc egy vessző és azt követő szóköz text = 'András, Béla, Cecília, Domonkos, Ervin, Friderika, Géza, Helga, Ilona, János, Kálmán, László, Miranda, Nándor, Olga, Péter' wrap_text_test(text, range(30, 51, 10), ', ') # Eredmények: # A tördelendő szöveg: "András, Béla, Cecília, Domonkos, Ervin, Friderika, Géza, Helga, Ilona, János, Kálmán, László, Miranda, Nándor, Olga, Péter" # # Maximális sorhossz: 30 # ['András, Béla, Cecília', 'Domonkos, Ervin, Friderika', 'Géza, Helga, Ilona, János', 'Kálmán, László, Miranda', 'Nándor, Olga, Péter'] # Az egyes sorok hossza: 21 26 25 23 19 # ------------------------------ # András, Béla, Cecília # Domonkos, Ervin, Friderika # Géza, Helga, Ilona, János # Kálmán, László, Miranda # Nándor, Olga, Péter # # Maximális sorhossz: 40 # ['András, Béla, Cecília, Domonkos, Ervin', 'Friderika, Géza, Helga, Ilona, János', 'Kálmán, László, Miranda, Nándor, Olga', 'Péter'] # Az egyes sorok hossza: 38 36 37 5 # ---------------------------------------- # András, Béla, Cecília, Domonkos, Ervin # Friderika, Géza, Helga, Ilona, János # Kálmán, László, Miranda, Nándor, Olga # Péter # # Maximális sorhossz: 50 # ['András, Béla, Cecília, Domonkos, Ervin', 'Friderika, Géza, Helga, Ilona, János, Kálmán', 'László, Miranda, Nándor, Olga, Péter'] # Az egyes sorok hossza: 38 44 36 # -------------------------------------------------- # András, Béla, Cecília, Domonkos, Ervin # Friderika, Géza, Helga, Ilona, János, Kálmán # László, Miranda, Nándor, Olga, Péter |
Az első tesztben a szóhatároló karakterlánc az alapértelmezett szóköz, ami a szövegekben a leggyakoribb. A tesztet három sorhosszkorlátra futtattuk le. Nyilvánvaló, hogy minél hosszabb sort engedünk, annál kevesebb sorra kell az eredeti szöveget tördelni. Mindhárom esetben a követelményeknek megfelelően lettek a sorok előállítva.
A második tesztben a szóhatároló karakterlánc egy vessző és azt követő szóköz. Ez tipikusan felsorolásoknál fordul elő. A tesztet itt is három sorhosszkorlátra végeztük el, és látható, hogy ebben az esetben is a követelményeknek megfelelően tördelődtek a sorok.
Ebben a feladatban a karakterláncokkal és listákkal való műveletek voltak a középpontban. Mindezekről a Python tudásépítés lépésről lépésre című e-könyvben elsősorban a „Beépített konténerobjektumok”, „Műveletek” és a „Beépített típusok nyilvános metódusai” fejezetekben lehet részleteiben olvasni.