Unicode


Unicode og ordinaler

Som alle andre datatyper i Python er også strenger egentlig representert under panseret som en sekvens av 0 og 1. For eksempel representeres bokstaven 'A' som 1000001 og bokstaven 'B' som 1000010. Hvis vi i stedet for å tolke sekvensen av 0 og 1 som en bokstav later som sekvensen er et tall i totall-systemet, får vi henholdsvis 65 for 'A' og 66 for 'B'.

På denne måten er hvert eneste symbol (bokstav og tegn, emoji og andre symboler som kan opptre i en streng) knyttet til et tall. Dette tallet kalles en ordinal for symbolet. Hvordan symboler matcher ordinaler gjøres (nå) på en standardisert måte som kalles Unicode. Unicode er med andre ord en matching mellom ordinal og symbol. Under viser vi et lite utdrag.

Ordinal Symbol
65 'A'
66 'B'
67 'C'
90 'Z'
198 'Æ'
216 'Ø'
197 'Å'
Ordinal Symbol
97 'a'
98 'b'
99 'c'
122 'z'
230 'æ'
248 'ø'
229 'å'
Ordinal Symbol
9 '\t' (tab)
10 '\n' (linjeskift)
32 ' ' (mellomrom)
33 '!'
48 '0'
49 '1'
50 '2'
128013 '🐍'

For å finne ordinalen til et symbol kan vi bruke funksjonen ord:

symbol = 'A'
ordinal = ord(symbol)
print('Ordinal til', symbol, 'er' , ordinal) # Ordinal til A er 65

For å konvertere fra ordinal til symbol («character») kan vi bruke funksjonen chr:

ordinal = 97
symbol = chr(ordinal)
print('Ordinal', ordinal, 'har symbol', symbol) # Ordinalen 97 har symbol a
Tekstkoding

Ett symbol kan representeres som ett tall, som vist i forrige avsnitt. Men hva om det er flere symboler etter hverandre, som i en streng eller en fil med tekst? Fordi det ikke eksisterer noe naturlig «mellomrom» i noe som representeres som en sekvens av 0 og 1, må vi bestemme oss for noen regler for å skille hvor ett symbol slutter fra hvor det neste starter.

Det finnes flere ulike strategier for dette, som vi kaller koding av en streng (engelsk: encoding). Kodinger som støtter alle Unicode-symboler begynner med «UTF» (Unicode Transformation Format).

Eksempler på kodinger:

ASCII er en gammel standard som Unicode-ordinalene er bakoverkompatibel med. Den deler opp sekvensen av 0’er og 1’ere i blokker på akkurat 8 biter, og så tolker den hver blokk som en ordinal oppgitt i totallsystemet. Hver blokk begynner alltid med 0. Eksempler noen ulike symboler og hvordan de kodes i ASCII:

Symbol Unicode Koding i ASCII
\n 10 00001010
A 65 01000001
B 66 01000010
Æ 198 ikke støttet
🐍 128013 ikke støttet

Den delen av kodingen som er markert i gult over er selve ordinalen (i totallsystemet). Nullene som kommer foran dette bare fyller opp plassen slik at blokken får størrelse på 8 bit.

  • Fordeler med ASCII: lett å forstå og implementere. Bruker lite lagringsplass. Støttes også av svært gamle systemer.

  • Ulemper med ASCII: Støtter kun symboler med unicode-ordinal under 128. Altså ingen støtte for norske bokstaver æ, ø og å.

UTF-32 er en koding som er enkel å forstå (men som i praksis er lite brukt). Den deler opp sekvensen av 0’er og 1’ere i blokker på akkurat 32 biter, og så tolker den hver blokk som en ordinal oppgitt i totallsystemet (akkurat som ASCII, altså, men tar større plass). Eksempler noen ulike symboler og hvordan de kodes i UTF-32:

Symbol Unicode Koding i UTF-32
\n 10 00000000000000000000000000001010
A 65 00000000000000000000000001000001
B 66 00000000000000000000000001000010
Æ 198 00000000000000000000000011000110
🐍 128013 00000000000000011111010000001101

Den delen av kodingen som er markert i gult over er selve ordinalen (i totallsystemet). Nullene som kommer foran dette bare fyller opp plassen slik at blokken får størrelse på 32 bit.

  • Fordeler med UTF-32: lett å forstå og implementere. Man kan raskt finne ut hvilken bokstav som er i en gitt posisjon. Støtter alle Unicode-symboler.

  • Ulemper med UTF-32: bruker mye unødvendig lagringsplass. Ikke bakoverkompatibel med ASCII.

UTF-8 er den vanligste unicode-kodingen. Den deler opp sekvensen av 0’er og 1’ere i blokker på 8 biter; de vanligste symbolene bruker bare én slik blokk, mens de mer sjeldne bruker flere blokker. Eksempler på hvordan noen ulike symboler blir kodet i UTF-8:

Symbol Unicode Koding i UTF-8
\n 10 00001010
A 65 01000001
B 66 01000010
Æ 198 11000011 10000110
🐍 128013 11110000 10011111 10010000 10001101

Den delen av kodingen som er markert i gult over er selve ordinalen (i totallsystemet). Den delen av kodingen som er markert i rødt inneholder informasjon som UTF-8 bruker for å avgjøre hvor mange blokker symbolet består av. De øvrige nullene bare fyller opp plassen slik at hver blokk får en størrelse på 8 bit.

  • Fordeler med UTF-8: Er bakoverkompatibel med den eldre standarden ASCII. Bruker mindre lagringsplass enn UTF-16 og UTF-32. Støtter alle Unicode-symboler. Benyttes nå som standard på internett.

Når man leser eller skriver en tekstfil, må man velge hvilken koding man skal benytte.

Hvis du ikke vet hvilken koding som er brukt, prøv disse ekodingene først: UTF-8 (anbefalt), Windows-1252 (også kalt cp1252), ISO 8859-1 (også kalt Latin-1), Windows-1251 (også kalt cp1251), UTF-16 og UTF-32. Hvis teksten er på et spesielt språk kan du også søke på internett etter kodinger som er vanlige for det språket.

# Eksempel på å skrive til en fil
writing_text = "Dette er en tekst. Den har æøå og 🐍 i seg."
with open("myfile.txt", "w", encoding="utf-8") as f:
    f.write(writing_text)

# Eksempel på å lese fra en fil
with open("myfile.txt", "r", encoding="utf-8") as f:
    reading_text = f.read()
print(reading_text) # Dette er en tekst. Den har æøå og 🐍 i seg.

Dersom du ikke angir noe for encoding= vil Python bruke standarden for ditt operativsystem. Dette er vanligvis utf-8 på Mac og Linux, og cp1252 på Windows, men kan også variere basert på «locale» -konfigurasjonen av operativsystemet (språk, etc.). Det er derfor lurt å alltid spesifisere encoding= når du skriver til/leser fra filer, slik at du ikke får problemer når du bytter operativsystem.