Itt vagy: Kezdőlap Ugorj fejest a Python 3-ba

Nehézségi szint: ♦♦♦♢♢

Karakterláncok

Azért mondom, mert az egyik barátom vagy.
Az én ábécém ott kezdődik, ahol a tiéd véget ér!
– Dr. Seuss, On Beyond Zebra!

 

Unalmas dolgok, amelyeket meg kell értened a fejesugrás előtt

Kevesen gondolnak bele, de a szöveg hihetetlenül bonyolult. Kezdjük az ábécével. Bougainville lakosai rendelkeznek a világ legrövidebb ábécéjével, az ő Rotokas ábécéjük csak 12 betűből áll: A, E, G, I, K, O, P, R, S, T, U és V. A spektrum másik végén a kínai, japán, és koreai nyelvek állnak, több ezer karakterrel. Az angol természetesen 26 betűt tartalmaz – 52-t, ha a kis- és nagybetűket külön számolod – , valamint néhány !@#$%& írásjelet.

Amikor „szövegről” beszélsz, akkor valószínűleg „a számítógéped képernyőjén megjelenő karakterekre és szimbólumokra” gondolsz. De a számítógépek nem karaktereket és szimbólumokat kezelnek, hanem biteket és bájtokat. Minden szöveg, amit valaha a számítógép képernyőjén láttál, valójában egy adott karakterkódolásban van tárolva. Nagy vonalakban a karakterkódolás biztosítja a leképezést a képernyőn látható és a számítógép által a memóriában és lemezen tárolt dolgok között. Számos különböző karakterkódolás létezik, egyesek adott nyelvekre vannak optimalizálva, például oroszra, kínaira vagy angolra, míg mások több nyelven is használhatók.

A valóság ennél bonyolultabb. Sok karakter több kódolásban is közös, de az egyes kódolások eltérő bájtsorozatokat használhatnak ezen karakterek tárolására a memóriában vagy a lemezen. A karakterkódolásra emiatt egyfajta visszafejtési kulcsként gondolhatsz. Amikor valakitől kapsz egy bájtsorozatot – egy fájlt, weboldalt, akármit – és azt mondja, hogy ez „szöveg”, akkor a bájtok karakterekké dekódolásához tudnod kell, hogy melyik karakterkódolást használta. Ha rossz kulcsot kapsz, vagy nem is kapsz kulcsot, akkor magadra maradsz a kód feltörésének irigylésre nem méltó feladatával. Esélyes, hogy elrontod, az eredmény pedig értelmetlen zagyvaság lesz.

Bizonyára láttál már olyan weboldalakat, mint ez, amelyek fura kérdőjelszerű karaktereket tartalmaztak az aposztrófok vagy az ékezetes betűk helyén. Ez általában azt jelenti, hogy az oldal szerzője nem adta meg a karakterkódolását, a böngésződ pedig csak találgatni tudott, amelynek eredménye várt és váratlan karakterek keveréke lett. Angolul az ilyesmi csak zavaró, de más nyelveken, például magyarul az eredmény teljesen olvashatatlan is lehet.

A világ minden jelentős nyelvéhez léteznek karakterkódolások. Mivel minden nyelv különböző, és a memória- és lemezterület történelmileg drága volt, minden karakterkódolás az adott nyelvre van optimalizálva. Ez alatt azt értem, hogy minden kódolás ugyanazokat a számokat(0–255) használta az adott nyelv karaktereinek ábrázolására. Például valószínűleg ismered az ASCII kódolást, amely az angol karaktereket 0 - 127 közti számokként tárolja. (A 65 a nagybetűs „A”, a 97 a kisbetűs „a” stb.) Az angol ábécé nagyon egyszerű, így teljes egészében leírható kevesebb, mint 128 számmal. Azok számára, akik tudnak 2-es alapon számolni, ez egy bájt 8 bitjéből 7-et jelent.

Az olyan nyugat-európai nyelvek, mint a francia, spanyol és német, több betűvel rendelkeznek, mint az angol. Pontosabban vannak mellékjelekkel kombinált betűik, mint a ñ karakter a spanyolban. A leggyakoribb kódolás ezekhez a nyelvekhez a CP-1252, amelyet „windows-1252”-nek is neveznek, mert széles körben használatos Microsoft Windowson. A CP-1252 kódolás átveszi az ASCII kódolás által a 0–127 tartományban használt karaktereket, de aztán kiterjed a 128–255 tartományra az olyan karakterekhez, mint az n hullámvonallal (241), ü (252) stb. Ez továbbra is egybájtos kódolás, a legnagyobb lehetséges szám, a 255 továbbra is elfér egy bájton.

Egyes nyelvek, például a kínai, japán és koreai olyan sok karakterrel rendelkeznek, hogy több-bájtos karakterkészleteket igényelnek. Ez azt jelenti, hogy minden„karaktert” egy kétbájtos szám képvisel 0–65535 között. De a különböző több-bájtos kódolások ugyanazzal a problémával szembesülnek, mint a különböző egybájtos kódolások, vagyis hogy mind ugyanazokat a számokat használja különböző értelmű dolgokra. Egyszerűen csak a számok tartománya nagyobb, mert sokkal több karaktert kell ábrázolni.

Ez nagyjából rendben volt a hálózatok előtti világban, ahol a „szöveget” magadnak írtad be, és néha kinyomtattad. Nem volt sok„sima szöveg”. A forráskód ASCII volt, és mindenki más szövegszerkesztőket használt, amelyek saját (nem szöveges) formátumokat használtak, amelyek nyilvántartották a karakterkódolási információkat a gazdag formázási stílusokkal stb. együtt. Ezeket a dokumentumokat ugyanazzal a szövegszerkesztővel olvasták, mint az eredeti szerző, így minden működött, többé-kevésbé.

Most gondolj az olyan globális hálózatok felemelkedésére, mint az e-mail és a web. Rengeteg „sima szöveg” repüli körbe a földgolyót, amelyeket az egyik számítógépen írnak, a másikon továbbítanak, a harmadikon pedig fogadnak és megjelenítenek. A számítógépek csak számokat látnak, de a számok különböző dolgokat jelenthetnek. Jaj ne! Mit kéne csinálni? Nos, a rendszereket arra kellett tervezni, hogy minden „sima szöveggel” együtt átvigyék a kódolási információkat. Ne feledd, a visszafejtési kulcs képezi le a számítógépek által olvasható számokat az ember által olvasható karakterekre. Egy hiányzó visszafejtési kulcs téves, olvashatatlan vagy még rosszabb szöveget eredményez.

Most gondolj arra, hogy egy helyen több szövegdarabot kell tárolni, például ugyanabban az adatbázistáblában, amely az általad valaha kapott összes e-mailt tárolja. Ekkor is tárolni kell a karakterkódolást minden szövegdarab mellett, hogy megfelelően jeleníthesd meg. Az hiszed ez nehéz? Próbálj meg az e-mail adatbázisodban keresni, ez több kódolás közti menet közbeni konvertálást jelent. Ugye milyen jól hangzik?

Most gondolj a többnyelvű dokumentumok lehetőségére, ahol több nyelv karakterei vannak egymás mellett ugyanabban a dokumentumban. (Tipp: az ezzel próbálkozó programok általában escape kódokat használtak a „módok” közti váltáshoz. Puff, most orosz koi8-r módban vagy, így a 241 jelentése Я; puff, most Mac Greek módban vagy, így a 241 jelentése ώ.) És természetesen keresni is akarsz azokban a dokumentumokban is.

Most elbőgheted magad, mert minden, amit a karakterláncokról tudni véltél, téves, és nincs olyan, hogy „sima szöveg”.

Unicode

Színre lép a Unicode.

A Unicode rendszert arra tervezték, hogy minden nyelv minden karakterét ábrázolni tudja. A Unicode minden betűt, karaktert vagy ideogrammát egy 4 bájtos számként ábrázol. Minden szám egy egyedi karaktert képvisel, amelyet legalább egy nyelvben használnak. (Nem minden szám van használatban, de több, mint 65535, így 2 bájt nem lenne elég.) A több nyelvben használt karakterek általában ugyanazzal a számmal rendelkeznek, kivéve ha komoly etimológiai érvek szólnak ez ellen. Ennek ellenére karakterenként pontosan egy szám van, és számonként pontosan egy karakter. Minden szám mindig egy dolgot jelent; nincsenek nyilvántartandó „módok”. Az U+0041 mindig az 'A', még ha egy adott nyelvben nincs is 'A' karakter.

A felszínen ez jó ötletnek tűnik. Egy kódolás mind felett. Több nyelv ugyanabban a dokumentumban. Nincs több „módváltás” a kódolások adatfolyamon belüli váltásához. De azonnal adja magát a nyilvánvaló kérdés. Négy bájt? Minden egyes karakterhez Ez rettenetesen pazarlónak tűnik, különösen olyan nyelvekhez, mint az angol vagy a spanyol, amelyek egy bájtnál (256 számnál) is kevesebbet igényelnek minden lehetséges karakter leírásához. Valójában még az ideogrammákat használó nyelvek (mint a kínai) esetén is pazarló, mert ezekhez sem kell karakterenként két bájtnál több soha.

Van egy Unicode kódolás, amely karakterenként négy bájtot használ. A neve UTF-32, mert 32 bit = 4 bájt. Az UTF-32 egy magától értetődő kódolás; veszi az összesUnicode karaktert (egy 4 bájtos szám), és azt a karaktert ugyanazzal a számmal ábrázolja. Ennek vannak előnyei, a legfontosabb, hogy egy karakterlánc N. karakterét állandó idő alatt lehet megtalálni, mert az N. karakter a 4×N. bájtnál kezdődik. Van sok hátránya is, a legnyilvánvalóbb, hogy négy nyomorult bájtot igényel minden nyomorult karakter tárolásához.

Noha rengeteg Unicode karakter van, a legtöbben gyakorlatilag nem fognak soha semmit használni az első 65535-ön kívül. Emiatt létezik egy másik Unicode kódolás is, az UTF-16 (mert 16 bit = 2 bájt). Az UTF-16 minden karaktert 0–65535 között tárol két bájton, és piszkos trükköket használ, ha a ritkán használt, „asztrálsíkon” lévő Unicode karaktereket kell ábrázolnod a 65535 fölött. A legnyilvánvalóbb előny: Most az UTF-16 kétszer olyan helytakarékos, mint az UTF-32, mert minden karakter tárolása pontosan két bájtot igényel csak négy bájt helyett (kivéve amelyiké nem). És még mindig egyszerűen és konstans idő alatt megtalálható egy karakterlánc N. karaktere, ha feltételezzük, hogy a karakterlánc nem tartalmazza az asztrálsíkon lévő karakterek egyikét sem. Ez egy jó feltételezés, egészen addig, amíg már nem.

Azonban az UTF-32 és az UTF-16 egyaránt rendelkezik nem nyilvánvaló hátrányokkal. A különböző számítógéprendszerek az egyes bájtokat különböző módokon tárolják. Ez azt jelenti, hogy az U+4E2D karakter UTF-16 használatakor tárolható 4E 2D vagy 2D 4E formában is, attól függően, hogy a rendszer big-endian vagy little-endian. (Az UTF-32 esetén még több lehetséges bájtsorrend van.) Amíg a dokumentumaid soha nem hagyják el a számítógéped, biztonságban vagy – ugyanazon számítógép különböző alkalmazásai ugyanazt a bájtsorrendet használják. Azonban abban a percben, hogy dokumentumokat akarsz rendszerek között átvinni, mondjuk valamilyen világszintű hálózaton, akkor jelezned kell a bájtjaid tárolási sorrendjét. Ellenkező esetben a fogadó rendszer nem fogja tudni, hogy a 4E 2D kétbájtos sorozat jelentése U+4E2D vagy U+2D4E.

Ennek a problémának a megoldásához a több-bájtos Unicode kódolások definiálnak egy „bájtsorrendjelet”, amely egy speciális nem nyomtatható karakter. Ezt a dokumentum elején elhelyezve jelezheted a bájtok sorrendjét. Az UTF-16 esetén a bájtsorrendjel az U+FEFF. Ha egy FF FE bájtokkal kezdődő UTF-16 dokumentumot kapsz, akkor a bájtsorrend az egyik, ha az FE FF bájtokkal kezdődik, akkor a bájtsorrend a másik.

Az UTF-16 ezzel együtt sem teljesen ideális, különösen ha rengeteg ASCII karakterrel dolgozol. Ha belegondolsz, akkor még egy kínai weboldal is rengeteg ASCII karaktert fog tartalmazni – a nyomtatható kínai karaktereket körülvevő összes elemet és attribútumot. Az N. karakter konstans idő alatti megtalálása szép dolog, de még itt van az asztrálsíkon lévő karakterek kellemetlen problémája, ami miatt nem tudod garantálni, hogy minden karakter pontosan két bájtos, emiatt nem lehet valóban megtalálni az N. karaktert konstans idő alatt, hacsak nem tartasz fenn egy külön indexet. És tudod, annyi de annyi ASCII szöveg van a világban…

Mások is gondolkoztak ezeken a kérdéseken, és kitaláltak egy megoldást:

UTF-8

Az UTF-8 egy változó hosszúságú kódolási rendszer a Unicode-hoz. Ez azt jelenti, hogy különböző karakterek különböző számú bájtot foglalnak. Az ASCII karakterekhez (A-Z stb.) az UTF-8 karakterenként csak egy bájtot használ. Tulajdonképpen pontosan ugyanazokat a bájtokat használja. Az UTF-8 első 128 karaktere (0–127) megkülönböztethetetlen az ASCII-étól. A „kiterjesztett latin” karakterek, mint a ñ és ö két bájtot foglalnak. (A bájtok nem egyszerűen az Unicode kódpontot jelentik, mint UTF-16 esetén; komoly bittologatás is szerepet kap.) A kínai karakterek, mint a 中 három bájtot foglalnak. A ritkán használt „asztrálsík” karakterek négy bájtot.

Hátrányok: mivel minden karakter különböző számú bájtot foglalhat, az N. karakter megkeresése egy O(N) művelet – azaz minél hosszabb a karakterlánc, annál tovább tart egy adott karakter megkeresése. Ezen kívül bittologatás szükséges a karakterek bájtokká kódolásához és a bájtok visszafejtéséhez karakterekké.

Előnyök: az általános ASCII karakterek kódolása szuperhatékony. Nem rosszabb az UTF-16-nál a kiterjesztett latin karakterek esetén. Jobb az UTF-32-nél a kínai karakterekhez. Ezen túl (és ezt el kell hinned nekem, mert nem fogom megmutatni a matekját) pontosan a bittologatás természete miatt nincsenek problémák a bájtsorrendből. Egy UTF-8 kódolású dokumentum pontosan ugyanazt a bájtsorozatot használja minden számítógépen.

Ugorj fejest

A Python 3-ban minden karakterlánc Unicode karakterek sorozata. Nincs olyan, hogy UTF-8 kódolású Python karakterlánc, vagy CP-1252 kódolású Python karakterlánc. Az „UTF-8 ez a karakterlánc?” kérdés érvénytelen. Az UTF-8 a karakterek bájtok sorozataként való kódolásának módja. Ha egy adott karakterláncot át szeretnél alakítani adott karakterkódolású bájtok sorozatává, akkor a Python 3 megoldja. Ha egy adott bájtsorozatot karakterlánccá szeretnél alakítani, akkor a Python 3 azt is megoldja. A bájtok nem karakterek, a bájtok bájtok. A karakter egy absztrakció. Egy karakterlánc ezen absztrakciók sorozata.

>>> s = '深入 Python'     
>>> len(s)               
9
>>> s[0]                 
'深'
>>> s + ' 3'             
'深入 Python 3'
  1. Egy karakterlánc létrehozásához zárd azt idézőjelek közé. A Python karakterláncok meghatározhatók egyszeres (') vagy dupla idézőjelekkel (").
  2. A beépített len() függvény visszaadja a karakterlánc hosszát, azaz a karakterek számát. Ez ugyanaz a függvény, amit a listák, tuple-ök, halmazok vagy szótárak hosszának meghatározására használtál. A karakterlánc olyan, mint egy karaktertuple.
  3. Ahogy a listák egyes elemei, úgy a karakterláncok egyes karakterei is elérhetők indexelés használatával.
  4. Ahogyan listákat, úgy a karakterláncokat is összefűzheted a + operátor használatával.

Karakterláncok formázása

Vessünk még egy pillantást a humansize.py programra:

[a humansize.py letöltése]

SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],         
            1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}

def approximate_size(size, a_kilobyte_is_1024_bytes=True):
    '''Egy fájlméret emberek által olvasható formába konvertálása.          

    Kulcsszó argumentumok:
    size -- a fájlméret bájtban
    a_kilobyte_is_1024_bytes -- ha True (alapértelmezett), akkor az 1024 többszöröseit használja
                                ha False, akkor az 1000 többszöröseit használja

    Visszaad: karakterláncot

    '''                                                                     
    if size < 0:
        raise ValueError('a szám nem lehet negatív')                        

    multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
    for suffix in SUFFIXES[multiple]:
        size /= multiple
        if size < multiple:
            return '{0:.1f} {1}'.format(size, suffix)                       

    raise ValueError('a szám túl nagy')
  1. 'KB', 'MB', 'GB'… ezek mind karakterláncok.
  2. A függvény docstringjei is karakterláncok. Ez a docstring többsoros, emiatt három egymás utáni idézőjelet használ a karakterlánc kezdésére és befejezésére.
  3. Ez a három egymás utáni idézőjel zárja a docstringet.
  4. Ez egy újabb karakterlánc, emberek által olvasható hibaüzenetként átadva a kivételnek.
  5. Ez egy… hé, hát ez meg mi?

A Python 3 támogatja az értékek karakterláncokba formázását. Noha ez nagyon bonyolult kifejezéseket is tartalmazhat, a legalapvetőbb felhasználási módja egy értéknek helykitöltőt tartalmazó karakterláncba való beszúrása.

>>> felhasználó = 'mark'
>>> jelszó = 'PapayaWhip'                               
>>> "{0} jelszava ez: {1}".format(felhasználó, jelszó)  
"mark jelszava ez: PapayaWhip"
  1. Nem, a jelszavam igazából nem PapayaWhip.
  2. Rengeteg minden történik itt. Először is, ez egy metódushívás egy karakterliterálon. A karakterláncok objektumok, és az objektumoknak metódusaik vannak. Másodszor, az egész kifejezés egy karakterlánccá értékelődik ki. Harmadszor, a {0} és a {1} helyettesítőmezők, amelyeket a format() metódusnak átadott argumentumok helyettesítenek.

Összetett mezőnevek

Az előző példa a legegyszerűbb esetet mutatja be, ahol a helyettesítőmezők egyszerű egészek. Az egész helyettesítőmezők helyzeti indexekként vannak kezelve a format() metódus argumentumlistájában. Ez azt jelenti, hogy a {0} az első argumentummal lesz helyettesítve (felhasználó ebben az esetben), a {1} a második argumentummal lesz helyettesítve (jelszó) stb. Annyi helyzeti indexed lehet, ahány argumentumod van, és annyi argumentumod lehet, amennyit csak akarsz. De a helyettesítőmezők ennél sokkal hatékonyabbak.

>>> import humansize
>>> si_suffixes = humansize.SUFFIXES[1000]      
>>> si_suffixes
['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
>>> '1000{0[0]} = 1{0[1]}'.format(si_suffixes)  
'1000KB = 1MB'
  1. A humansize modul valamelyik függvényének hívása helyett csak az általa definiált egyik adatszerkezetet használjuk: az „SI” utótagok (ezek 1000 hatványai) listáját.
  2. Ez bonyolultnak tűnik, de nem az. A {0} a format() metódusnak elsőként átadott argumentumra, az si_suffixes-re hivatkozik. De az si_suffixes egy lista. Így a {0[0]} a lista első elemére hivatkozik, ez lesz a format() metódusnak átadott első argumentum: 'KB'. Ezalatt a {0[1]} ugyanazon lista második elemére hivatkozik: 'MB'. A kapcsos zárójeleken kívül minden – beleértve az 1000-t, az egyenlőségjelet és a szóközket – érintetlen. A végeredmény a következő karakterlánc:'1000KB = 1MB'.

Ez a példa azt mutatja meg, hogy a formátumelőírások az adatszerkezetek elemeit és tulajdonságait (majdnem) Python szintaxissal tudják elérni. Ezeket összetett mezőneveknek hívjuk. A következő összetett mezőnevek „egyszerűen csak működnek”:

Csak hogy ne alhass nyugodtan, itt egy példa, amely a fentiek mindegyikét kombinálja:

>>> import humansize
>>> import sys
>>> '1MB = 1000{0.modules[humansize].SUFFIXES[1000][0]}'.format(sys)
'1MB = 1000KB'

Így működik:

Formátum-előírások

Várj csak! Van még más is! Nézzük meg újra ezt a fura sort a humansize.py fájlból:

if méret < multiple:
    return '{0:.1f} {1}'.format(méret, utótag)

Az {1} a format() metódusnak átadott második argumentumra lesz cserélve, amely az utótag. De mi ez a {0:.1f}? Ez két dolog: a {0}, amit már felismersz, és a :.1f, amit még nem. A második fele (a kettőspont és ami utána áll) definiálja a formátum-előírást, amely tovább finomítja a helyettesített változó formázásának módját.

A formátum-előírások lehetővé teszik a helyettesítőszöveg változatos módokon való megpiszkálását, mint a C printf() függvényében. Hozzáadhatsz nulla- vagy szóközkitöltést, igazíthatod a karakterláncokat, befolyásolhatod a tizedesjegyek számát, és akár hexadecimálissá is alakíthatsz számokat.

A helyettesítőmezőn belül egy kettőspont (:) jelöli a formátum-előírás kezdetét. A „.1” formátum-előírás „a legközelebbi tizedesre kerekítést” jelent (azaz csak egy számjegy jelenik meg a tizedesvessző után). Az „f” formátum-előírás „fixpontos számot” jelöl (nem pedig exponenciális jelölést vagy más decimális ábrázolást). Emiatt a 698.24 méret és a 'GB' utótag esetén a formázott karakterlánc '698.2 GB' lesz, mert a 698.24 egy tizedesjegyre lesz kerekítve, majd az utótag a szám mögé lesz fűzve.

>>> '{0:.1f} {1}'.format(698.24, 'GB')
'698.2 GB'

A formátum-előírásokkal kapcsolatos véres részletekért olvasd el a Format Specification Mini-Language oldalt a hivatalos Python dokumentációban.

Egyéb gyakori karakterlánc-metódusok

A formázás mellett a karakterláncok sok más hasznos trükköt is tudnak.

>>> s = '''A befejezett tanul-         
... mányok több évnyi tudományos mun-
... ka és az évek tapasztala-
... tának egyesített eredménye.'''
>>> s.splitlines()                     
['A befejezett tanul-',
 'mányok több évnyi tudományos mun-',
 'ka és az évek tapasztala-',
 'tának egyesített eredménye.']
>>> print(s.lower())                   
a befejezett tanul-
mányok több évnyi tudományos mun-
ka és az évek tapasztala-
tának egyesített eredménye.
>>> s.lower().count('m')               
4
  1. Az interaktív Python parancsértelmezőben beírhatsz többsoros karakterláncokat is. Miután elkezdtél egy többsoros karakterláncot a tripla idézőjellel, nyomd meg az ENTERT, és az interaktív parancsértelmező a karakterlánc folytatását fogja várni. A záró tripla idézőjel beírása befejezi a karakterláncot, és a következő ENTER végrehajtja a parancsot (ebben az esetben a karakterlánc hozzárendelését az s változóhoz).
  2. A splitlines() metódus egy többsoros karakterláncot vár, és karakterláncok listáját adja vissza, az eredeti minden sorához egyet rendelve. Ne feledd, hogy a sorok végén lévő kocsivissza karaktereket ez nem tartalmazza.
  3. A lower() metódus az egész karakterláncot kisbetűssé alakítja. (Hasonlóan, az upper() metódus egy karakterláncot nagybetűssé alakít.)
  4. A count() metódus megszámolja egy részkarakterlánc előfordulásainak számát. Igen, ebben a mondatban tényleg négy „m” van!

Itt van még egy gyakori eset. Mondjuk, hogy van egy kulcs-érték párokat tartalmazó listád, a következő formátumban: kulcs1=érték1&kulcs2=érték2; és fel szeretnéd darabolni ezeket, hogy az egészet betehesd egy {kulcs1: érték1, kulcs2: érték2} alakú szótárba.

>>> lekérdezés = 'felhasználó=pilgrim&adatbázis=master&jelszó=PapayaWhip'
>>> a_list = lekérdezés.split('&')                                   
>>> a_list
['felhasználó=pilgrim', 'adatbázis=master', 'jelszó=PapayaWhip']
>>> a_list_of_lists = [v.split('=', 1) for v in a_list if '=' in v]  
>>> a_list_of_lists
[['felhasználó', 'pilgrim'], ['adatbázis', 'master'], ['jelszó', 'PapayaWhip']]
>>> a_dict = dict(a_list_of_lists)                                   
>>> a_dict
{'jelszó': 'PapayaWhip', 'felhasználó': 'pilgrim', 'adatbázis': 'master'}
  1. A split() karakterlánc-metódus egy kötelező argumentummal, a határolóval rendelkezik. A metódus a karakterláncot a határoló alapján karakterláncok listájává darabolja. Itt a határoló az & karakter, de bármi lehet.
  2. Most van egy karakterlánclistánk, mindegyikhez tartozik egy kulcs, amelyet egy egyenlőségjel és végül egy érték követ. Egy listafeldolgozó segítségével bejárjuk a teljes listát, és minden karakterláncot az első egyenlőségjelnél kétfelé vágunk. A split() metódus elhagyható második argumentuma a szétvágások kívánt száma. Az 1 „csak egy szétvágást” jelent, így asplit() metódus egy kételemű listát fog visszaadni. (Elméletileg egy érték is tartalmazhat egyenlőségjelet. Ha a 'kulcs=érték=valami'.split('=') hívást használtad volna, akkor a ['kulcs', 'érték', 'valami'] háromelemű listát kaptad volna.)
  3. Végül a Python ezt a listák listáját szótárrá változtatja a dict() függvénynek való átadással.

Az előző példa nagyon úgy néz ki, mint egy URL lekérésparamétereinek feldolgozása, de a valós életben az URL-feldolgozás valójában ennél sokkal bonyolultabb. Ha URL-lekérdezésparaméterekkel dolgozol, akkor jobban jársz az urllib.parse.parse_qs() függvénnyel, amely kezel néhány nem nyilvánvaló határesetet is.

Karakterlánc szeletelése

Miután definiáltál egy karakterláncot, bármely részét megkaphatod új karakterláncként. Ezt a karakterlánc szeletelésének nevezzük. A szeletelés pontosan ugyanúgy működik, mint a listák szeletelése, ami logikus is, hiszen a karakterláncok pusztán karakterek sorozatai.

>>> a_string = 'Az én ábécém ott kezdődik, ahol a tiéd véget ér.'
>>> a_string[6:12]           
'ábécém'
>>> a_string[6:-6]           
'ábécém ott kezdődik, ahol a tiéd vég'
>>> a_string[0:2]            
'Az'
>>> a_string[:25]            
'Az én ábécém ott kezdődik'
>>> a_string[25:]            
', ahol a tiéd véget ér.'
  1. Egy karakterlánc „szeletnek” nevezett bármely részét megkaphatod két index megadásával. A visszatérési érték egy új karakterlánc, amely a karakterlánc minden elemét az eredeti sorrendben tartalmazza az első szeletindextől kezdve.
  2. A listák szeleteléséhez hasonlóan negatív indexeket is használhatsz a karakterláncok szeleteléséhez.
  3. A karakterláncok indexelése nullától kezdődik, így az a_string[0:2] a karakterlánc első két elemét adja vissza az a_string[0] elemtől az a_string[2] elemig, de az utóbbit már nem tartalmazza.
  4. Ha a bal oldali szeletindex a 0, akkor kihagyható, és a Python a 0-t feltételezi. Így az a_string[:25] ugyanaz, mint az a_string[0:25] mert a kezdő 0-t a Python feltételezi.
  5. Hasonlóan, ha a jobb oldali szeletindex az utolsó elem indexe, akkor kihagyható. Így az a_string[25:] ugyanaz, mint az a_string[25:48], mert ez a karakterlánc 48 karaktert tartalmaz. Van itt egy kellemes szimmetria. Ebben a 48 karakteres karakterláncban az a_string[:25] visszaadja az első 25 karaktert, és az a_string[25:] visszaad mindent az első 25 karakter kivételével. Tulajdonképpen az a_string[:n] mindig az első n karaktert adja vissza, az a_string[n:] pedig a többit, a karakterlánc hosszától függetlenül.

Karakterláncok és bájtok

A bájtok bájtok; a karakterek absztrakciók. Unicode karakterek megváltoztathatatlan sorozatát karakterláncnak hívjuk. A 0 és 255 közötti számok megváltoztathatatlan sorozatát bájtobjektumnak hívjuk.

>>> by = b'abcd\x65'  
>>> by
b'abcde'
>>> type(by)          
<class 'bytes'>
>>> len(by)           
5
>>> by += b'\xff'     
>>> by
b'abcde\xff'
>>> len(by)           
6
>>> by[0]             
97
>>> by[0] = 102       
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'bytes' object does not support item assignment
  1. Egy bájtobjektum definiálásához használd a b''bájtliterál” szintaxist. A bájtliterálon belül minden bájt lehet egy ASCII karakter, vagy egy kódolt hexadecimális szám \x00 és \xff (0–255) között.
  2. A bájtobjektum típusa bytes.
  3. A listákhoz és karakterláncokhoz hasonlóan a beépített len() függvénnyel lekérheted a bájtobjektum hosszát.
  4. A listákhoz és karakterláncokhoz hasonlóan használhatod a + operátort a bájtobjektumok összefűzésére. Az eredmény egy új bájtobjektum.
  5. Egy 5 bájtos bájtobjektum és egy 1 bájtos bájtobjektum összefűzése egy 6 bájtos bájtobjektumot eredményez.
  6. A listákhoz és karakterláncokhoz hasonlóan a bájtobjektum egyes bájtjai elérhetők indexelés használatával. Egy karakterlánc elemei karakterláncok, egy bájtobjektum elemei egészek. Egész pontosan 0–255 közti egészek.
  7. Egy bájtobjektum megváltoztathatatlan, nem adhatsz értéket az egyes bájtoknak. Ha az egyes bájtokat kell módosítanod, akkor használhatsz karakterláncszeletelést és összefűzési operátorokat (ezek ugyanúgy működnek, mint a karakterláncok), vagy átalakíthatod a bájtobjektumot bájttömb objektummá.
>>> by = b'abcd\x65'
>>> btmb = bytearray(by)  
>>> btmb
bytearray(b'abcde')
>>> len(btmb)             
5
>>> btmb[0] = 102         
>>> btmb
bytearray(b'fbcde')
  1. Egy bájtobjektum megváltoztatható bájttömb objektummá alakításához használd a beépített bytearray() függvényt.
  2. Minden, a bájtobjektumokon használható metódus és művelet működik bájttömb objektumokon is.
  3. Az egyetlen különbség, hogy bájttömb objektum esetén értékeket rendelhetsz az egyes bájtokhoz indexelés használatával. A hozzárendelt értéknek egy 0–255 közti egésznek kell lennie.

Az egyetlen dolog, amit soha nem csinálhatsz, az a bájtok és karakterláncok keverése.

>>> by = b'd'
>>> s = 'abcde'
>>> by + s                       
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to str
>>> s.count(by)                  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bytes' object to str implicitly
>>> s.count(by.decode('ascii'))  
1
  1. Nem fűzhetsz össze bájtokat és karakterláncokat. Ez két külön adattípus.
  2. Nem számolhatod meg a bájtok előfordulásait egy karakterláncban, mert a karakterláncban nincsenek bájtok. Egy karakterlánc karakterek sorozata. Talán „egy adott bájtsorozat adott karakterkódolással való visszafejtése után kapott karakterlánc előfordulásait” akartad megszámolni? Nos, akkor kifejezetten azt kell kérned. A Python 3 nem fog közvetlenül bájtokat karakterláncokká vagy karakterláncokat bájtokká alakítani.
  3. Csodálatos véletlen folytán ez a sor kód „egy adott bájtsorozat adott karakterkódolással való visszafejtése után kapott karakterlánc előfordulásait” számolja meg.

Itt jön a kapcsolat a karakterláncok és a bájtok között: a bájtobjektumok rendelkeznek egy decode() metódussal, amely egy karakterkódolást vár, és visszaad egy karakterláncot, a karakterláncok pedig rendelkeznek egy encode() metódussal, amely egy karakterkódolást vár és egy bájtobjektumot ad vissza. Az előző példában a dekódolás viszonylag magától érthetődő volt – egy ASCII kódolású bájtsorozat átalakítása történt karakterek sorozatává. De ugyanez a folyamat történik bármely kódolással, amley támogatja a karakterlánc karaktereit – még az örökölt(nem Unicode) kódolások esetén is.

>>> a_string = '深入 Python'           
>>> len(a_string)
9
>>> by = a_string.encode('utf-8')    
>>> by
b'\xe6\xb7\xb1\xe5\x85\xa5 Python'
>>> len(by)
13
>>> by = a_string.encode('gb18030')  
>>> by
b'\xc9\xee\xc8\xeb Python'
>>> len(by)
11
>>> by = a_string.encode('big5')     
>>> by
b'\xb2`\xa4J Python'
>>> len(by)
11
>>> roundtrip = by.decode('big5')    
>>> roundtrip
'深入 Python'
>>> a_string == roundtrip
True
  1. Ez egy karakterlánc. Kilenc karakterből áll.
  2. Ez egy bájtobjektum. 13 bájtból áll. Ez az a bájtsorozat, amelyet az a_string UTF-8-ba kódolásakor kapsz.
  3. Ez egy bájtobjektum. 11 bájtból áll. Ez az a bájtsorozat, amelyet az a_string GB18030-ba kódolásakor kapsz.
  4. Ez egy bájtobjektum. 11 bájtból áll. Ez egy teljesen eltérő bájtsorozat, amelyet az a_string Big5-ba kódolásakor kapsz.
  5. Ez egy karakterlánc. Kilenc karakterből áll. Ez az a karaktersorozat, amelyet a by Big5 kódolási algoritmus használatával való dekódolásakor kapsz. Ez megegyezik az eredeti karakterlánccal.

Utóirat: a Python forráskód karakterkódolása

A Python 3 feltételezi, hogy a forráskódod – azaz minden .py fájl – UTF-8 kódolású.

A Python 2-ben a .py fájlok alapértelmezett kódolása ASCII volt. A Python 3-ban az alapértelmezett kódolás az UTF-8.

Ha másik kódolást szeretnél használni a Python kódodon belül, akkor elhelyezhetsz egy kódolásdeklarációt az egyes fájlokon belül. Ez a deklaráció a .py fájlt windows-1252 kódolásúként definiálja:

# -*- coding: windows-1252 -*-

Technikailag a karakterkódolás felülbírálása a második sorban is lehet, ha az első sor egy UNIX-stílusú shebang parancs.

#!/usr/bin/python3
# -*- coding: windows-1252 -*-

További információkért olvasd el a PEP 263: Defining Python Source Code Encodings dokumentumot.

További olvasnivaló

A Unicode-ról a Pythonban:

A Unicode-ról általában:

A karakterkódolásról más formátumokban:

Karakterláncokról és azok formázásáról:

© 2001–11 Mark Pilgrim