Tilbake
1.4

1.4 Strenger, f-strenger og formatert utskrift

Strengoperasjoner, f-strenger med formatspesifikatorer, og `print` med `end`/`sep` — utskriftsdetaljene sensor krever nøyaktig.

45 min
7 oppgaver
Strengerf-strengerformatert utskrift
Din fremgang i kapitlet
0 / 7 oppgaver
Forkunnskaper:

- Kap. 1.1 — Variabler, datatyper, uttrykk og operatorpresedens: at '3' og 3 er to ulike verdier, og at print skiller argumentene sine med ett mellomrom.
- Kap. 1.2 — Lister, indeksering og slicing: indeksering og slicing — de samme reglene gjelder for strenger.
- Kap. 1.3 — Løkker: for-løkker, som vi bruker til å skrive ut tabeller.

Løkke 1 — Strengen er en sekvens (~10 min)

Målestasjonen leverer én linje per døgn, og den ser slik ut:

Blindern 21.5 4.0

Alt du har er tekst. Skal du regne på tallene, må du først dele opp linja, rydde vekk usynlige tegn, og konvertere til tall. Det er hele fillesingsoppgaven i miniatyr, og den begynner med at en streng er en sekvens av tegn — helt som en liste.

Strengen som sekvens

En streng er en ordnet rekke tegn, og alt du kan gjøre med en liste av indeksering og slicing, kan du gjøre med en streng.

tekst[0] er første tegn, tekst[-1] er siste, tekst[1:4] er et utsnitt på tre tegn, og tekst[::-1] er teksten baklengs. len(tekst) er antall tegn, mellomrom medregnet.

Én forskjell fra lister: indeksering i en streng gir en streng (av lengde 1), ikke en annen datatype. Det finnes ingen egen «tegn»-type i Python.

Strenger er immutable

En streng kan ikke endres etter at den er laget. tekst[0] = 'A' stopper programmet med en TypeError.

Alle strengmetodene du møter nedenfor — .strip(), .replace(), .upper()returnerer en ny streng og lar den gamle være. Derfor må du ta imot resultatet: tekst = tekst.strip(). Å skrive bare tekst.strip() som en egen linje gjør ingenting, og det er en stille feil som koster poeng i fillesingsoppgaver.

`+` og `*` på strenger
+ skjøter sammen: 'ab' + 'cd' gir 'abcd'. * gjentar: '-' * 5 gir '-----'.

Begge operandene til + må være strenger. 'sum: ' + 4 stopper programmet med en TypeError — du må skrive 'sum: ' + str(4), eller helst bruke en f-streng. Gjentakelsen med * er derimot praktisk til å lage skillelinjer i en tabell.

`v in tekst`

På strenger er in en delstreng-test, ikke en elementtest: 'ind' in 'Blindern' er True.

Det er en viktig forskjell fra lister, der in bare finner hele elementer. Testen skiller mellom store og små bokstaver, så 'blindern' in 'Blindern' er False.

`len(tekst)`

Antall tegn i strengen, medregnet mellomrom og eventuelle usynlige tegn som linjeskift.

Det er nettopp derfor len er et diagnoseverktøy ved fillesing: er lengden én mer enn du forventet, henger det sannsynligvis et linjeskift på slutten, og da trenger du .strip().

✏️Eksempel 1: Strengen behandlet som en liste av tegn

Hva skriver programmet ut?

navn = 'Blindern'
print(navn[0], navn[-1])
print(navn[1:4])
print(len(navn))
print(navn[::-1])
print('ind' in navn, 'X' in navn)
print('-' * 8)

Utskrift:

B n
lin
8
nrednilB
True False
--------

Alt her er reglene fra kap. 1.2, brukt på tegn i stedet for på tall: navn[1:4] gir tre tegn fordi slutten er eksklusiv, og navn[::-1] snur rekkefølgen.

Merk at utskriften ikke har fnutter rundt seg. Fnuttene finnes bare i koden.

📝Oppgave 1

(Innstegsoppgave — minimal sporing. Sjanger A — kodesporing, altså «hva skriver programmet ut?».) La tekst = 'Tryvann'.

a) Hva gir tekst[0]?

b) Hva gir tekst[-2]?

c) Hva gir len(tekst)?

d) Hva gir 'van' in tekst?

Løkke 2 — Å dele opp og rydde en tekstlinje (~10 min)

Nå til de fire metodene du får bruk for i hver eneste fillesingsoppgave. Rekkefølgen er alltid den samme: rydd, del opp, konverter.

`.split(sep)`

Deler strengen i en liste av delstrenger. Med et argument deles den på nøyaktig det tegnet: 'a;b;c'.split(';') gir ['a', 'b', 'c'].

Uten argument deles den på vilkårlig blanktegn — ett eller flere mellomrom, tabulator eller linjeskift — og eventuelle blanktegn i begge ender kastes. Det gjør linje.split() robust mot ujevn kolonnebredde.

Fellen: bruker du bar split() på en fil der feltene er skilt med semikolon, får du én lang delstreng i stedet for flere. Det er feilkode #8, og den slår først ut når du prøver å konvertere til tall. Bruk split(';') når separatoren er et bestemt tegn.

`.strip()`

Fjerner blanktegn i begge ender av strengen og returnerer en ny streng. Blanktegn inne i strengen røres ikke.

Den viktigste jobben .strip() gjør, er å fjerne linjeskiftet som følger med hver linje du leser fra fil. Uten den blir det siste feltet '4.0\n' i stedet for '4.0', og float klarer faktisk det — men int('4\n') og enhver sammenligning med en tekstverdi gjør det ikke. Å glemme .strip() er feilkode #7.

`sep.join(liste)`

Motstykket til split: skjøter sammen elementene i en liste av strenger til én streng, med sep mellom. ';'.join(['a', 'b']) gir 'a;b'.

Merk hvor separatoren står: den er strengen du kaller metoden , ikke et argument. Og alle elementene må være strenger — ', '.join([1, 2]) stopper programmet. Er de tall, må du gjøre dem om først.

`.index(delstreng)`

Gir posisjonen der delstrengen begynner: 'Blindern'.index('n') gir 2, altså den første forekomsten.

Finnes ikke delstrengen, stopper programmet med en ValueError. Vil du bare vite om den finnes, bruk in — den gir True/False og feiler aldri.

`.lower()`, `.upper()` og `.replace()`
.lower() og .upper() gir en ny streng med bare små eller bare store bokstaver. De brukes til å gjøre en sammenligning uavhengig av store bokstaver: svar.lower() == 'ja'.

.replace(gammel, ny) bytter ut alle forekomster og gir en ny streng: '12,5'.replace(',', '.') gir '12.5'. Nettopp den konverteringen trenger du hvis en datafil bruker komma som desimalskilletegn, for float('12,5') stopper programmet.

✏️Eksempel 2: Fra tekstlinje til tall

Én linje fra målestasjonen ser slik ut, med et linjeskift på slutten:

  Blindern ; 21.5 ; 4.0

Skriv koden som henter ut stasjonsnavnet og de to tallene.

Rekkefølgen er rydd, del opp, konverter — og hvert felt må ryddes for seg, fordi det står mellomrom rundt semikolonene:

linje = '  Blindern ; 21.5 ; 4.0\n'
deler = linje.split(';')
print(deler)
navn = deler[0].strip()
temp = float(deler[1])
vind = float(deler[2])
print(navn, temp, vind)
print(len(deler), len(navn))

Utskrift:

['  Blindern ', ' 21.5 ', ' 4.0\n']
Blindern 21.5 4.0
3 8

Tre ting å legge merke til:

1. Utskriften av deler viser hvor mye søl som ligger i feltene: mellomrom foran og bak, og linjeskiftet i det siste feltet. Fnuttene og \n synes fordi Python viser lister med kodeformen til hvert element.
2. float tåler blanktegn rundt tallet, så float(' 21.5 ') går fint. Men navn må ryddes med .strip(), ellers får du to mellomrom foran.
3. Hadde vi brukt bar linje.split() her, ville vi fått fem deler — Blindern, ;, 21.5, ;, 4.0 — og feil felt på hver plass. Det er feilkode #8.

📝Oppgave 2

(Midtveisnivå, sjanger A.) Hva skriver programmet ut?

linje = 'sol;regn;sno'
deler = linje.split(';')
print(deler)
print(len(deler))
print(deler[1].upper())
print('-'.join(deler))

Løkke 3 — F-strenger: å sette verdier inn i tekst (~12 min)

— naturlig pausepunkt —

Nå skal utskriften bli pen. En f-streng er en streng med f foran fnuttene, der alt du setter i krøllparentes blir regnet ut og satt inn. Det er den moderne, korte måten, og det er den sensor forventer.

F-streng `f'{x}'`

En streng med f rett foran fnutten. Inne i krøllparentesene kan du skrive hvilket som helst uttrykk, og verdien settes inn i teksten.

navn = 'Blindern'
temp = 21.5
print(f'{navn}: {temp} grader')
print(f'{navn} har {len(navn)} tegn, og {temp} + 1 er {temp + 1}')

Utskrift:

Blindern: 21.5 grader
Blindern har 8 tegn, og 21.5 + 1 er 22.5

Merk at f her er et prefiks på en streng, ikke en variabel. Det har ingenting å gjøre med funksjonen f som du skriver i ODE-oppgavene i kap. 7.1 — se advarselen om navnekollisjonen nedenfor.

Bredde og desimaler: `f'{x:8.3f}'`

Etter kolon kommer formatangivelsen. f'{x:8.3f}' betyr: bredde 8, 3 desimaler, f for fast desimalform.

- Bredden er totalt antall tegn feltet skal fylle, medregnet desimalpunktet og eventuelt minustegn. Er tallet kortere, fylles det ut med mellomrom foran (høyrejustert). Er det lengre, får det stå — bredden er et minimum, ikke et maksimum.
- Desimalene er alltid nøyaktig så mange som du ber om, med avrunding: f'{2.5:.0f}' gir 2, og f'{1.0:.3f}' gir 1.000.

Bredden er den som overses. f'{2.5:8.3f}' gir 2.500 med tre mellomrom foran, og de mellomrommene er en del av utskriften.

Heltall og eksponentform: `f'{n:3d}'` og `f'{x:.3e}'`
d er for heltall: f'{7:3d}' gir 7 med to mellomrom foran, altså bredde 3. Bruker du d på et flyttall, stopper programmet.

e er eksponentform: f'{1234.5:.3e}' gir 1.234e+03 — ett siffer foran punktet, tre etter, og eksponenten med fortegn og minst to siffer. Den brukes til å vise svært små eller svært store tall, for eksempel en feil på 10710^{-7}.

✏️Eksempel 3: En tabell med f-strenger

En tabell over potenser av 2, med fast kolonnebredde. Hva skriver programmet ut?

for k in range(4):
    print(f'{k:2d}:{2**k:5.2f}', end=' | ')
print()

Utskrift:

 0: 1.00 |  1: 2.00 |  2: 4.00 |  3: 8.00 | 

Sporingstavle

Rundekf'{k:2d}'2**kf'{2**k:5.2f}'Legges til
10 0 (ett mellomrom foran)1 1.00 (ett mellomrom foran) 0: 1.00 \|
21 12 2.00 1: 2.00 \|
32 24 4.00 2: 4.00 \|
43 38 8.00 3: 8.00 \|

Regnestykket for bredden: 1.00 er fire tegn, og bredde 5 gir derfor ett mellomrom foran. 0 er ett tegn, og bredde 2 gir ett mellomrom foran.
Fordi end=' | ' erstatter linjeskiftet, havner alt på én linje, og linja avsluttes av det tomme print(). Legg merke til at det også står | etter den siste kolonnen — end gjelder hver runde, også den siste.
📝Oppgave 3

(Midtveisnivå, sjanger A — formatert utskrift.) Hva skriver programmet ut? Skriv utskriften nøyaktig, med mellomrom.

x = 3.14159
print(f'{x:.2f}')
print(f'{x:8.3f}')
print(f'{x:.0f}')
print(f'{42:5d}|')

Løkke 4 — print i detalj: end, sep og hvordan Python viser verdier (~10 min)

Til slutt de tre detaljene som avgjør flest kodesporingsoppgaver i hele faget.

`print(..., end=...)`
end er det print skriver etter argumentene. Standardverdien er linjeskift, '\n'.

Setter du end=' ', forsvinner linjeskiftet og neste utskrift fortsetter på samme linje. Setter du end='', kommer ingenting imellom i det hele tatt. Et tomt print() skriver bare linjeskiftet og brukes til å avslutte en linje du har bygget opp med end.

Dette er halve feilkode #16: en sporing der du skriver tre linjer i stedet for én, er feil selv om tallene er riktige.

`print(..., sep=...)`
sep er det som skrives mellom argumentene. Standardverdien er ett mellomrom.

print(1, 2, 3, sep=';') gir 1;2;3, og print('a', 'b', sep='') gir ab. Merk at sep bare virker mellom argumenter — har print bare ett argument, har sep ingen effekt i det hele tatt. Det er en fin distraktor.

Hvordan Python viser en verdi
print viser en streng uten fnutter, men en liste med fnutter rundt hvert strengelement.

Grunnen er at Python har to visningsformer: den lesbare (som print bruker på selve argumentet) og kodeformen (som brukes på elementer inne i en samling). Derfor:

print('sol')
print(['sol', 'regn'])
print(3.0, [3.0])

Utskrift:

sol
['sol', 'regn']
3.0 [3.0]

Regelen å ta med: lister skrives med hakeparenteser, komma og mellomrom, og strenger inne i dem beholder fnuttene.

Escape-sekvenser `\n` og `\t`

Inne i en streng betyr \n linjeskift og \t tabulator. Det er to tegn i koden, men ett tegn i verdien — len('a\tb') er 3.

Tabulator hopper til neste faste kolonne og brukes til å justere tabeller:

print('navn\tgrader')
print('Blindern\t21.5')
print(len('a\tb'))

Utskrift:

navn	grader
Blindern	21.5
3

Trenger du en backslash i selve teksten, skriver du \\. I bokas egen kode holder vi oss til fire mellomrom som innrykk og bruker aldri tabulator i Python-kildekoden (feilkode #24).

✏️Eksempel 4: `end` og `sep` i samme program

Fire linjer med print, tre ulike innstillinger. Hva skriver programmet ut?

print('a', 'b')
print('a', 'b', sep='')
print(1, 2, 3, sep=' ; ')
for i in range(3):
    print(i, end='')
print()
print('slutt', end='!')

Utskrift:

a b
ab
1 ; 2 ; 3
012
slutt!

- print('a', 'b') gir mellomrommet Python setter inn av seg selv.
- sep='' fjerner det.
- sep=' ; ' setter inn hele den strengen mellom tallene — merk mellomrommene på begge sider.
- Løkka med end='' skriver tre sifre uten noe imellom og uten linjeskift; det tomme print() avslutter linja.
- Siste linje slutter med ! og ikke med linjeskift.

At det ikke kommer noe linjeskift til slutt, er verdt å merke seg i sporing: utskriften er slutt! uten mer.

📝Oppgave 4

(Midtveisnivå, sjanger A — end og sep.) Hva skriver programmet ut? Skriv utskriften nøyaktig, med mellomrom og linjeskift slik terminalen viser den.

for i in range(3):
    print(i, i*i, sep=':', end=' ')
print()
print('a', 'b', 'c', sep='')

📝Oppgave 5

(Midtveisnivå, sjanger A — strenger og lister i utskrift.) Hva skriver programmet ut?

ord = 'regn i mars'
deler = ord.split()
print(deler)
print(len(deler), len(ord))
print(deler[0][0], ord[0])
print(ord.replace(' ', '_'))

📝Oppgave 6
Eksamensnivå, sjanger A

Hva skriver programmet ut? Skriv utskriften nøyaktig; marker mellomrom nøye.

navn = ['Blindern', 'Tryvann']
temp = [21.5, 17.25]
for n, t in zip(navn, temp):
    print(f'{n:10s}{t:6.1f}')
print(f'{"sum":10s}{sum(temp):6.1f}')

📝Oppgave 7
Eksamensnivå, sjanger A

Hva skriver programmet ut?

linje = '  Bygdoy ; 12,5 ; 3 \n'
deler = linje.split(';')
navn = deler[0].strip()
temp = float(deler[1].strip().replace(',', '.'))
antall = int(deler[2].strip())
print(len(deler))
print(f'[{navn}]')
print(temp, antall)
print(f'{navn.upper()}: {temp:5.2f} ({antall:2d})')

API- og konstruksjonsliste

Begrepsbank

Begrepsbanken er flashcard-/repetisjonsstoff — den gjentar det du nettopp har lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet gjelder kjernestoffet.

Tom streng `''`

Strengen uten tegn. len('') er 0, og den regnes som falsk i en ja/nei-test, akkurat som den tomme lista.

Den oppstår oftere enn du tror: 'a;;b'.split(';') gir ['a', '', 'b'], altså med en tom streng i midten. Ved fillesing er en tom linje derfor noe du må håndtere før du prøver å konvertere til tall.

Tekst mot tall
'12' og 12 er to helt ulike verdier. Tekst kan skjøtes og gjentas; tall kan legges sammen og ganges.

Alt som kommer inn utenfra — fra kommandolinjen (kap. 2.1), fra input, fra en fil (kap. 8.1) — er tekst, og må konverteres med int eller float før du kan regne. Glemmer du det, får du '12' + '5' som blir '125' i stedet for 17. Det er en av de faste feilene i «finn feilen»-oppgaver.

Fnutter: enkle eller doble?
'sol' og "sol" er samme verdi. Valget er praktisk: skal teksten inneholde en apostrof, bruker du doble fnutter, og omvendt.

Boka bruker enkle fnutter som standard, fordi det er den vanlige stilen i fagets fasitkode. Inne i en f-streng må du dessuten passe på: bruker du enkle fnutter utenfor, må du bruke doble inni krøllparentesene, som i f'{"sum":10s}'.

Repetisjon — de fem setningene som må sitte

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.

Skolesaga er en uavhengig læringsressurs og er ikke tilknyttet eller godkjent av Universitetet i Oslo. Dette er ikke offisielt studiemateriell. Les mer.