STRING

**Autor : Ognjen Radovic**

## **4.1. Dosadne stvari koje morate da shvatite pre nego što uronite**

Da li ste znali da ljudi iz Bungavila imaju najmanju azbuku na svetu? Njihov Rotokas
azbuka je sastavljena od samo 12 slova: A, E, G, I, K, O, P, R, S, T, U i V. Sa druge strane
jezici poput kineskog, japanskog i korejskog imaju hiljade znakova. Engleski, naravno ima
26 slova - 52 ako ubrojite vekaraktera i mala slova odvojeno - plus jos mnogo znakova interpukcije ! @ # $% &

Kada ljudi govore o „tekstu“, oni misle na „znakove i simbole na ekranu računara.“ Ali
računari ne rade sa  znakovima i simbolima; oni rade sa bitovima i bajtovima. Svaki deo teksta koji ste ikada
videli na ekranu računara zapravo je smešteno u određen koder znakova. Grubo rečeno
Kodiranje znakova omogućava putanju između stvari koje vidite na ekranu i vaše stvari
računar se zapravo čuva u memoriji i na disku. Postoji mnogo različitih šifriranja karaktera, neke
optimizovani za određene jezike poput ruskog ili kineskog ili engleskog i drugi  koji se mogu koristiti
na više jezika.

U stvarnosti je mnogo složenije od toga. Mnogo znakova je zajedničko za više kodiranja, ali svako
kodiranje može koristiti različitu sekvencu bajtova da bi se ti znakovi zapravo spremili u memoriju ili na disk.
Tako možete da razmišljate o kodiranju znakova kao o ključu za dešifrovanje. Kad god vam neko da
sekvencu bajtova - fajl, veb stranicu... - i tvrdi da je to „tekst“, morate znati koji znak
kodiranja su koristili  pri kodiranju tako da možete dekodirati bajtove u znakove. Ako vam daju pogrešan ključ ili vam ga ne daju
uopšte, na vama  je da sami dekodirate kod. Verovatno ćete pogrešiti , i
rezultat će biti neispravan

106

Sve što si mislio da znaš o stringovima je pogrešno

Sigurno ste naišli na veb stranice poput ove, sa čudnim
znakovima u obkarakteru upitnika gde bi apostrofi trebali
biti.
To uglavnom znači da autor stranice nije podesio
ispravno kodiranje znakova, pa je vaš pregledač
nagađo, a rezultat je bio kombinacija očekivanih i
neočekivanih znakova. Na engleskom je jednostavno samo neugodno; na
drugim jezicima, rezultat može biti u potpunosti
nečitljiv.

Kodiranje znakova postoji za svaki veći jezik
u svetu. Pošto se svaki jezik razkarakteruje i
memorija i prostor na disku su uvek bili skupi,
svako kodiranje znakova optimizovano je za određeno
Jezik. Pod tim se misli na svako kodiranje koristi iste
brojeve (0–255) koji predstavljaju znakove tog jezika.
Na primer, verovatno ste upoznati sa ASCII
kodiranje, u kojem se engleska slova čuvaju kao brojevi
u rasponu od 0 do 127. (65 je vekaraktero „A“, 97 su
mala slova „a“ i c.) Engleski jezik ima vrlo jednostavnu azbuku,
pa se može u potpunosti izraziti u manje od 128 brojeva. Za one od vas koji mogu računati u sistemu sa bazom 2,
to je 7 od 8 bita u bajtu.

Zapadnoevropski jezici poput Francuskog, Španskog i Nemačkog imaju više slova nego engleski. Zapravo
imaju slova kombinovana sa različitim dijakritičkim oznakama, poput znaka ñ  na španskom. Najviše
zastupljeno kodiranje za ove jezike je CP-1252, koji se takođe naziva i „Windows-1252“, jer je široko rasprostranjen na
Microsoft Windowsu. CP-1252 kodiranje deli znakove sa ASCII u rasponu 0–127, ali tada
širi raspon na 128–255 za znakove poput n-sa-tildom-preko-njega (241), u-sa-dve tačke-iznad-njega (252),
& c. To je još uvek jednobajtno kodiranje; najveći mogući broj, 255, još uvek se uklapa u jedan bajt.
Zatim postoje jezici poput kineskog, japanskog i korejskog, koji imaju tokaraktero mnogo znakova da i oni
zahtevaju višebajtne skupove znakova. Odnosno, svaki „znak“ je predstavljen dvobajtnim brojem od
0–65535. Ali različiti dekoderi sa više bajta i dalje imaju isti problem kao i različiti jednobajtni enkodovi,
naime, svaki od njih koristi iste brojeve koji znače različite stvari. Kod njih je samo raspon brojeva širi
jer postoji mnogo više karaktera.

107
To je uglavnom bilo u redu u neumreženom svetu, gde je „tekst“ bio nešto što ste upisali i štampali sami.
Nije bilo mnogo „čistog teksta“. Izvorni kod je bio ASCII, a svi ostali su upotrebljavali
procesore reči, koji su definisali svoje vlastite (ne-tekstualne) formate koji su pratili informaciju o kodiranju znakova
sa bogatim stajlingom i c. Ljudi čitaju te dokumente upotrebom istog programa za obradu teksta kao i originalni
autore, pa je sve manje-više funkcionisalo,

Sada razmislite o usponu globalnih mreža poput e-pošte i interneta. Mnogo "čistog teksta" se koristi
, Pisan na jednom računaru, prenosi se preko drugog računara i prima i prikazuje
trećim računarom. Računari mogu da vide samo brojeve, ali brojevi mogu značiti različite stvari. O, ne!
Šta da se radi? Pa, sistemi su morali da budu dizajnirani da nose informacije kodiranja zajedno sa svakim delom
„čistog teksta.“ Ne zaboravite, ključ za dešifrovanje povezuje karaktere razumne računaru i karaktere čitljive čoveku
Nedostajući ključ za dešifrovanje znači nečitljiv tekst.

Sada razmislite o mogućnosti skladištenja više komada teksta,  u istoj tabeli baze podataka
koja sadrži svu  primljenu e-poštu. I dalje morate da skladištite enkodrianje  pored svakog
dela čitljivog dela teksta . Razmisli? Pokušaj pretražiti bazu podataka e-pošte, koja
mora da pretvara između više kodiranja u letu. Da li to zvuči zabavno?

Sada razmislite o mogućnosti višejezičnih dokumenata na kojima su  karakteri iz nekokaraktero jezika
jedni  pored drugih u istom dokumentu.
(Savet: programi koji su to pokušali najčešće su koristilii kodove za bekstvo
prebacivanje „modova.“ Uf, ti si u ruskom koi8-r režimu, tako da 241 znači A; Uf, sada se govori na grčkom jeziku
, znači 241 znači ώ.).) I naravno, takođe ne želite da pretražujem te dokumente.
Sada plačite , jer sve što ste mislili da znate o stringovima je pogrešno, i  "čist tekst" ne postoji

## **4.2 Unikod**

Unesite unikod
108

Unicode je sistem dizajniran da predstavlja svaki karakter iz svakog jezika. Unicode predstavlja svako
slovo, karakter ili ideograf kao 4-bajtni broj. Svaki broj predstavlja jedinstveni znak koji se koristi u
bar u jednom od svetskih jezika. (Ne koriste se svi brojevi, ali njih više od 65535, dakle 2
bajtovi ne bi bili dovoljni.) Znakovi koji se koriste na više jezika uglavnom imaju isti broj,
osim ako postoji dobar etimološki razlog da se to tako ne radi. Bez obzira na to, postoji tačno jedan broj po znaku i
tačno jedan znak po broju. Svaki broj uvek ima samo jednu stvar; ne postoje „režimi“ koje treba pratiti
U + 0041 je uvek „A“, čak i ako jezik nema „A“.
То је sjajna ideja. Jedno kodiranje koje će svima njima vladati. Više jezika po
dokument. Nema više "prebacivanja režima" za prebacivanje između kodiranja u sred radnje. Očigledno
postavlja se jedno pitanje. Četiri bajta? Za svaki pojedini karakter? Izgleda stvarno bahato,
posebno za jezike poput engleskog i španskog, kojima je potrebno manje od jednog bajta (256 brojeva) da bi izrazili
svaki mogući karakter. Zapravo, rasipa se čak i za jezike zasnovane na ideografima (poput kineskog), kojim nikada
treba više od dva bajta po znaku.

Postoji Unicode kodiranje koje koristi četiri bajta po znaku. Zove se UTF-32, jer je 32 bita = 4
bajtova. UTF-32 je direktno kodiranje; uzima svaki Unicode znak (4-bajtni broj) i
predstavlja znak sa istim brojem. To ima neke prednosti, od kojih je najvažnija
možete naći N-ti znak niza u realnom vremenu, jer Nti znak počinje na 4 × Nti
bajt. Takođe ima par nedostataka, najočigledniji je da je potrebno četiri bajta da bi se skladištio svaki
čudni karakter.

Iako postoji puno Unicode karakterа, ispada da većina ljudi nikada ništa neće koristiti
izvan prvih 65535. Dakle, postoji još jedno kodiranje Unicode-a, koje se naziva UTF-16 (jer 16 bita = 2 bajta).
UTF-16 kodira svaki znak od 0–65535 kao dva bajta, a zatim koristi neke prljave hakove ako vam stvarno trebaju
da predstavljaju retko korišćene „astralne ravni“ Unicode znakovi koji prelaze 65535. Najočitija prednost:
UTF-16 je dvostruko manji od UTF-32, jer je za svaki znak potreban samo dva bajta
umesto četiri bajta . I još uvek lako možete pronaći N-ti karakter
stringa u stalnom vremenu, ako pretpostavite da niz ne sadrži bilo koji astralni ravni, što je a
dobra pretpostavka do momenta kada nije dobra.

Ali postoje i očigledni nedostaci i za UTF-32 i za UTF-16. Različiti računarski sistemi skladište
pojedinačne bajtove na različite načine. To znači da bi znak U + 4E2D bi mogao da bude sačuvan u UTF-16
4E 2D ili 2D 4E, zavisno od toga da li je sistem big-endian ili mali-endian. (Za UTF-32 postoje čak još
više mogućih rasporeda bajtova.) Sve dok dokumenti nikada ne napuste računar, vi ste
sigurni - različite aplikacije na istom računaru upotrebljavaće isti poredak bajta. Ali onog trenutka kada
želite da prenesete dokument između sistema, npr na mrežu,
treba vam način da naznačite u kom su redosledu su skladišteni vaši bajtovi. U suprotnom, prijemni sistem nema načina
da zna da li dvobajtni niz 4E 2D znači U + 4E2D ili U + 2D4E.
Da biste rešili ovaj problem, višebajtni kodovi Unicode definišu kao „Byte order Mark“, što je poseban karakter koji se ne može štampati i koji možete da dodate na početku svog dokumenta kako biste naznačili koji je nalog vaš
bajtovi su unutra.
Za UTF-16, marka za poredak bajtova je U + FEFF. Ako dobijete dokument UTF-16 koji počinje sa
bajtovi FF FE, znate da je redosled bajta jednosmerno; ako započne sa FE FF, znate da je redosled bajtova
obrnut.

Ipak, UTF-16 nije baš idealan, pogotovo ako imate posla sa mnogo ASCII znakova. Ako razmislite
čak i kineska veb stranica sadrži puno ASCII znakova - svih elemenata i atributa
okružujući kineske znakove za ispis. Lepo je kad možeš pronaći n-ti karakter u realnom vremenu,
ali još uvek postoji težak problem tih karakterova iz astralne ravni, što znači da ne možete da garantujete
da je svaki znak tačno dva bajta, tako da stvarno ne možete da pronađete N-ti znak u stalnom vremenu osim ako
zadržavate zaseban indeks. A sigurno ima puno ASCII teksta na ovom svetu ...

Drugi ljudi su razmišljali o tomei našli su rešenje:

UTF-8

110

UTF-8 je sistem kodiranja promenljive dužine za Unicode. Odnosno, različiti karakteri zauzimaju različit
broj bajtova. Za ASCII znakove (A-Z i c.) UTF -8 koristi se samo jedan bajt po znaku. U stvari, koriste se
potpuno isti bajtovi; prvih 128 znakova (0–127) u UTF -8 se ne razlikuju od ASCII. „Produženi
Latino ”znakovi poput n i o na kraju zauzimaju dva bajta. (Bajtovi nisu samo tačka koda
kao što su bili u UTF-16; uključeno je nekoliko ozbiljnih zavrzlama.) Kineski znakovi poput 中 na kraju
zauzimaju tri bajta. Retko korišteni karakteri „astralne ravni“ imaju četiri bajta.

Nedostaci: zato što svaki znak može imati različit broj bajtova, pronalaženje N-tog znaka je
O (N) operacija - duži string, duže traje period da bi se pronašao određeni znak. Takođe, postoji
zavrzlama koji su potrebni za kodiranje znakova u bajtove i dekodiranje bajtova u znakove.

Prednosti: super efikasno kodiranje uobičajenih ASCII znakova.ne manje loše od UTF-16 za produženi latinski jezik
karaktera i Bolje od UTF-32 za kineske znakove. Takođe (i moraćete da mi verujete zbog toga, jer
Neću da vam objašnjavam matematiku), zbog  prirode zavrzlama,ne postoje  problemi rasporeda bajtova.
Dokument kodiran u UTF -8 koristi isti raspored bajtova na bilo kojem računaru.

## **4.3. Zaranjanje**

U Pytonu 3, svi nizovi su sekvence Unicode znakova. Ne postoji  stvar kao što je Python string
kodiran u UTF -8 ili Python string kodiranom kao CP-1252. „Da li je ovaj string UTF -8?“ Je neispravno pitanje.
UTF -8 je način kodiranja znakova kao niz bajtova. Ako želite da uzmete niz i pretvorite ga u
sekvencu bajtova u određenom kodiranju znakova, Python 3 vam može pomoći u tome. Ako želite da uzmete
sekvencu bajtova i pretvorite ga u string, Python 3 vam takođe može pomoći u tome. Bajtovi nisu karakteri;
bajtovi su bajtovi. Karakteri su apstrakcija. String je sekvenca tih apstrakcija.

111

>>> s = '深入 Python' ①
>>> len(s) ②
9
>>> s[0] ③
'深'
>>> s + ' 3' ④
'深入 Python 3'

1. Da biste stvorili niz, zatvorite ga u navodnicima. Nizovi Python-a mogu se definisati jednimnavodnokom (') ili dvostrukim
navodnikom (").
2. Ugrađena funkcija len () vraća dužinu niza, tj. Broj znakova. Ovo je isto
funkciju koju koristite za pronalaženje dužine liste, tuplea, seta ili rečnika (dictionary). Niz je poput tuplea znakova.
3. Baš kao i uklanjanje pojedinačnih stavki sa liste, pojedinačni likovi se mogu izvući iz niza koristeći indeks
notaciju.
4. Baš kao i liste, možete povezati nizove pomoću operatora +.

## **4.4. Formatiranje Stringova**

Stringovi mogu da se definišu sa jednim ili dva dupla apostrofa

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):
**Convert a file size to human-readable form. ②
Keyword arguments:
size -- file size in bytes
a\_kilobyte\_is\_1024\_bytes -- if True (default), use multiples of 1024
if False, use multiples of 1000
Returns: string** ③
if size < 0:
raise ValueError('number must be non-negative') ④
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('number too large')

1. 'KB', 'MB', 'GB' ... to su stringovi
2. Funkcionalne docstringovi su stringovi. Ovaj docstring obuhvata više redova, pa koristi apostrofe u tri reda za početak
i završi stringova
3. Ovi apostrofi u tri reda završavaju docstring.
4. Postoji još jedan string, koji se kao izuzetak prenosi korisniku kao čitljiva poruka .
5. Postoji ... hej, sta je dodjavola to?

Python 3 podržava pretvaranja formatiranja  vrednosti u stringove. Iako ovo može da uključuje veoma komplikovane izraze,
najosnovnija upotreba je umetanje vrednosti u niz sa jednim rezerviranim mestom.

114

>>> username = 'mark'
>>> password = 'PapayaWhip' ①
>>> "{0}'s password is {1}".format(username, password) ②
"mark's password is PapayaWhip"

1. Ne, moja lozinka zaista nije PapayaVhip.
2. Ovde se puno toga događa. Prvo, to je poziv metode na literalnom stringu. Stringovi su objekti, a objekti imaju
metode. Drugo, ceo izraz vrednuje niz. Treće, {0} i {1} su rezervna polja, koja
zamenjuju se argumentima prosleđenim metodi format ().

## **4.4.1. Složena polja imena**

### Prethodni primer prikazuje najjednostavniji slučaj, gde su zamenska polja jednostavan celi brojevi. Integerzamenska polja tretiraju se kao pozicioni indeksi u listi argumenata metode format (). Toznači da se {0} zamenjuje prvim argumentom (korisničko ime u ovom slučaju), {1} se zamenjuje drugimargumentom (lozinka) i c. Možete imati onoliko indeksa pozicije koliko imate argumenata, a možete i njihonoliko argumenata koliko želite. Ali polja za zamenu su mnogo moćnija od toga.

>>> 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. Umesto da pozovete bilo koju funkciju u humansize modulu, samo ste ugrabili jednu od podataka koji
definiše: popis sufiksa „SI“ (powers-of-1000).
2. Ovo izgleda komplikovano, ali nije. {0} će se odnositi na prvi argument prosleđen metodi format (),
si\_suffikes. Ali si\_suffikes je lista. Dakle, {0 [0]} se odnosi na prvu stavku liste koja je prvi
argument prosleđen metodi format (): 'KB'. U međuvremenu, {0 [1]} se odnosi na drugu stavku iste
liste: 'MB'. Sve izvan vitičaste zagrade - uključujući 1000, znak jednake i razmake - ostaje netaknuto.
Krajnji rezultat je string  '1000KB = 1MB'.
115

{0} je zamenjen prvo sa format () argumentom.{1} je zamenjen sa drugim.

Ono što ovaj primer pokazuje jeste da format specifikator može da
pristupa stavkama i svojstvima strukture podataka koristeći
sintaksu Python. To se naziva složenim imenima polja.
Navedena složena polja imena rade:

• Donošenje liste i pristup listi stavki po indeksu
(kao u prethodnom primeru)
• Donošenje rečnika i pristup vrednostima
rečnik po ključu
• Pronalazak modula i pristup njegovim promenljivim i
funkcije po imenu
• Prenošenje instancije klase i pristup njenim svojstvima i
metodama po imenu
• Bilo koja kombinacija gore navedenog

Evo vam primer koji kombinuje sve gore navedeno:

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

Evo kako to funkcioniše:

• Sis modul sadrži informacije o trenutno pokrenutoj instanci Pythona. Pošto ste ga upravo uvezli,
možete proslediti sam sys modul kao argument metodi (() formatu). Dakle, polje za zamenu {0}
odnosi se na sys modul.
• sys.modules je rečnik svih modula koji su uvezeni u ovoj Python instanci. Ključevi su
modul se imenuju kao nizovi; vrednosti su sami modulski objekti. Dakle, polje za zamenu
{0.modules} odnosi se na rečnik uvezenih modula.

116

• sys.modules ['humansize'] je humansize modul koji ste upravo uveli. Polje za zamenu
{0.modules [humizeize}} se odnosi na humansize modul. Ovde imajte na umu malu razliku u sintaksi. U stvarnom
Python kodu, ključevi sys.modules rečnika su stringovi; da biste ih uputili, trebate da stavite apostrofe
oko naziva modula (npr. 'humansize'). Ali u polju za zamenu preskočite navodnike oko
imena ključnog rečnika (npr. humansize). Da citiram PEP 3101: Advanced String Formatting, „Pravila za raščlanjivanje
ključa za stavku je vrlo jednostavan. Ako počinje sa cifrom, tada se tretira kao broj, inače se koristi kao string."
• sys.modules ['humansize'] .SUFFIXES je rečnik definisan na vrhu humansize modula.
polje za zamenu {0. modules [humansize] .SUFFIXES} se odnosi na taj rečnik.
• sys.modules ['humansize]] SUFFIXES [1000] je lista sufiksa SI: [' KB ',' MB ',' GB ',' TB ',' PB ',' EB ',
'ZB', 'IB']. Dakle, polje za zamenu {0.modules [humize] .SUFFIXES [1000]} se odnosi na tu listu.
• sys.modules ['humansize']. SUFFIXES [1000] [0] je prva stavka na listi sufiksa SI: 'KB'. Stoga
kompletno polje za zamenu {0. modules [humansize] .SUFFIXES [1000] [0]} se zamenjuje dvoznačnim
stringom KB

**KRAJ**