Sõnetöötlus Pythonis19. Oct '14
Sissejuhatus
Sõnetöötlus Pythonis kätkeb endas elementaarseid tegevusi sõnedega (string):
Sõnede kokku kleepimine
Alamsõne otsimine
Sõnede lõikamine
Andmetüübid
Python 2.x defineerib kaks andmetüüpi mis mõlemad põlvnevad basestring andmetüübist: str mis võib sisaldada suvalisi baite ning unicode mis on ette nähtud unicode sümbolite hoiustamiseks. Ülakomasid kasutatakse str objekti instantseerimiseks, u tähega prefiksitud sõne viitab unicode objektile:
len("õ") # Tagastab 2
len("ẽ") # Tagastab 3
len(u"õ") # Tagastab 1
len(u"ẽ") # Tagastab 1
type("õ") # Tagastab <type 'str'>
type(u"õ") # Tagastab <type 'unicode'>
Siit on ka ilusti näha seda, et täht õ koosneb kahest baidist ning täht ẽ koosneb kolmest baidist. Alates aastast 2007 on utf-8 kasutus kasvanud järsult ning sellel on lihtne põhjus. Bait-sümbol vaste säilitavate tähetabelite kasutamine on keerukas ning seetõttu erikeelsete materjalide kombineerimine ühte faili on problemaatiline, eriti just veebis. Unicode tähetabel defineerib üle miljoni sümboli ning utf-8 kodeerib igaühte neist 1 kuni 6 baidi abil.
Python 3-s str andmetüüp toetab Unicode sümboleid vaikimisi ning b tähega prefiksitud baitide jada andmetüüp bytes on niiöelda eristaatuses:
len("ẽ") # Tagastab 1
len(b"a") # Tagastab 1
len(b"ẽ") # SyntaxError: bytes can only contain ASCII literal characters.
len("ẽ".encode("utf-8")) # Tagastab 3
Konverteerimine eri tähetabelite vahel
Baitide jada mis sisaldab UTF-8 kodeeringus teksti saab teisendada Unicode sõneks nii:
b = '\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82'
u = b.decode("utf-8")
u # Tagastab u'\u043f\u0440\u0438\u0432\u0435\u0442'
print u # Tagastab привет
Analoogselt saab näiteks UTF-16 kodeeringus baidijada teisendada Unicode sõneks nii:
b = '\xff\xfe?\x04@\x048\x042\x045\x04B\x04'
u = b.decode("utf-16")
u # Tagastabb u'\u043f\u0440\u0438\u0432\u0435\u0442'
print u # Tagastab привет
Samamoodi kui on vaja baite väljastada (nt. faili kirjutamisel) saab Unicode sõne teisendada ühte või teise kodeeringusse:
u"привет".encode("utf-8") # Tagastab '\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82'
u"привет".encode("utf-16") # Tagastab '\xff\xfe?\x04@\x048\x042\x045\x04B\x04'
u"привет".encode("utf-32") # Tagastab '\xff\xfe\x00\x00?\x04\x00\x00@\x04\x00\x008\x04\x00\x002\x04\x00\x005\x04\x00\x00B\x04\x00\x00'
u"привет".encode("cyrillic") # Tagastab '\xdf\xe0\xd8\xd2\xd5\xe2'
ISO8859 näiteks toetab täpitähti aga mitte kirillitsat:
u"jäääär".encode("iso8859") # Tagastab 'j\xe4\xe4\xe4\xe4r'
u"привет".encode("iso8859") # UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-5: ordinal not in range(256)
ASCII aga ei toeta kumbagi:
u"jäääär".encode("ascii") # UnicodeEncodeError: 'ascii' codec can't encode characters in position 1-4: ordinal not in range(128)
u"привет".encode("ascii") # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
Kui tagasiühilduvus pole probleemiks siis on tungivalt soovitatud UTF-8 kasutamine ning kus jõudlus on probleemiks soovitaks UTF-32 kodeeringut. Jõudlus tuleb muidugi keskeltläbi 3-4x rohkema kettakasutuse arvelt.
Sõnedega opereerimine
Pluss operaatorit saab kasutada sõnede kokku kleepimiseks (string concatenation):
s = u"salajane"
t = u"kalane"
s + t # Tagastab u'salajanekalane'
s + " " + t # Tagastab u'salajane kalane'
Üksiku sümboli eraldamiseks saab kasutada sisse-ehitatud [indeks] meetodit, indeksid kasvavad nullist liikudes vasakult paremale ning vähenevad miinus ühest liikudes paremalt vasakule:
s[0] # Tagastab esimese sümboli u's'
s[1] # Tagastab teise sümboli u'a'
s[-2] # Tagastab eelviimase sümboli u'n'
s[-1] # Tagastab viimase sümboli u'e'
Sõnest saab alamhulka (substring) leida sisse-ehitatud lõikamismeetodiga (string slicing) mille üldkuju on [algus:lõpp:samm]. Algus- ja lõpuindeksid jooksevad analoogselt eelmise koodinäitega. Indeksi märkimata jätmisel eeldatakse vastavalt algust või lõppu:
s[:4] # Tagastab u'sala' ehk alates algusest kuni neljanda sümbolini
s[-4:] # Tagastab u'jane' ehk alates lõpu poolt neljandast kuni lõpuni välja
s[1:6:2] # Tagastab u'aaa' ehk alates teisest sümbolist kuni kuuendani jättes vahele iga teise
Sõned on muutumatud (immutable) mis tähendab seda, et neid võib vabalt edasi anda teistele funktsioonidele muretsemata selle pärast, et funktsioon võib sõne sisu muuta:
s[0] = "x" # TypeError: 'unicode' object does not support item assignment
Järelikult sõne muutmisel tuleb vastavad alamsõned leida ning need üksteisega liita. Sõnede kokku kleepimisel luuakse alati uus objekt:
id(s) # Tagastab objekti s mäluaadressi
id(t) # Tagastab objekti t mäluaadressi
id(s+t) # Tagastab objekti s+t mäluaadressi
Seetõttu on suurema hulga (>miljon) sõnede kokku kleepimisel kasutada mõnda muud lähenemist:
"".join([s, t]) # Tagastab u'salajanekalane'
Alamsõne otsing
Alamsõne indeksit saab leida find() ning rfind() meetoditega:
s = "salajane"
s.find("a") # Tagastab 1
s.find("ja") # Tagastab 4
s.rfind("la") # Tagastab 2
s.rfind("a") # Tagastab 5
Alamsõnede hulka saab leida count() meetodiga:
s.count("a") # Tagastab 3
s.count("ja") # Tagastab 1
"ja" in s # Tagastab True
Sõnede vormindamine
Pythonis on mitu sõnede vormindamise meetodit. Üks populaarsemaid on % operaator mis jäljendab C-st tundud printf() funktsiooni käitumist:
failinimi = "Matrix.mkv"
gigabaite = 4.789654
sekundeid = 56
protsente = 67
u"Kopeerin faili %s, kopeeritud %.02fGB (%i%%), aega jäänud %i sekundit" % (failinimi, gigabaite, protsente, sekundeid)
# Tagastab u'Kopeerin faili Matrix.mkv, kopeeritud 4.79GB (67%), aega jäänud 56 sekundit'
Üksiku argumendi puhul võib sulud ära jätta:
import math
math.pi # Tagastab 3.141592653589793
u"Pii on umbkaudu %.02f" % pi # Tagastab u'Pii on umbkaudu 3.14'
Konverteerimine eri kooditabelite vahel
Python 2.x peal on veel terve hunnik mooduleid mis tagastavad vaikimisi str tüüpi sõnesid ning nendega on opereerimine raskendatud. Näiteks urllib moodulit saab kasutada veebiserveriga rääkimiseks, aga veebilehed on tavaliselt UTF-8 kodeeringus, mistõttu tuleb alla laaditud sõne dekodeerida UTF-8 kodeeringu järgi:
import urllib
h = urllib.urlopen("http://neti.ee/")
print "Server vastas:", h.getcode()
buf = h.read() # Puhvris on baidid!
print "Baite:", len(buf)
print "Unicode sümboleid:", len(buf.decode("utf-8"))
Annab käivitamiseks umbes järgneva vaste:
Server vastas: 200
Baite: 51347
Unicode sümboleid: 51188
Python 3-s on urllib moodul suuresti ringi tehtud 1.