Les 3
Strings en tekstverwerking in de diepte
Unicode, f-string-opmaak en stringmethodes voor echte teksten.
🎯 Na deze les kun je
- f-strings met opmaakcodes gebruiken
- Unicode en encodings uitleggen
- tekst opschonen en splitsen
Een groot deel van wat programma's doen, is tekst verwerken: namen netjes maken, een logregel uit elkaar halen, een rapport uitlijnen, een CSV-bestand van een ander systeem inlezen dat net een andere tekenset gebruikt. Je kent strings al uit de cursus Programmeerconcepten. In deze les leer je de gereedschappen die Python daarvoor heeft: opmaakcodes in f-strings, de belangrijkste string-methodes en hoe tekst als bytes wordt opgeslagen (encodings).
F-strings en formaatcodes
Een f-string vult waarden in tussen accolades. Na een dubbele punt kun je zeggen hoe de waarde getoond moet worden:
prijs = 1234.5
print(f"{prijs:.2f}") # 2 decimalen
print(f"{prijs:,.2f}") # met duizendtalscheiding
print(f"{0.0712:.1%}") # als percentage
print(f"{42:05d}") # aanvullen met nullen tot 5 tekens
1234.50
1,234.50
7.1%
00042
Uitlijnen werkt met < (links), > (rechts) en ^ (midden) plus een breedte. Handig voor tabellen:
producten = [("appel", 0.5), ("watermeloen", 3.25), ("kiwi", 0.3)]
for naam, prijs in producten:
print(f"{naam:<12}{prijs:>7.2f}")
print(f"[{'totaal':^19}]")
appel 0.50
watermeloen 3.25
kiwi 0.30
[ totaal ]
Bij het debuggen is = handig: het toont de expressie én de waarde.
aantal = 3
prijs = 0.5
print(f"{aantal=} {aantal * prijs=}")
aantal=3 aantal * prijs=1.5
De duizendtalscheiding is altijd een komma en het decimaalteken een punt, ongeacht je taalinstelling. Voor de Nederlandse notatie (1.234,50) is er een eenvoudige truc: f"{prijs:,.2f}".replace(",", "X").replace(".", ",").replace("X", "."). Voor echte meertalige programma's gebruik je de module locale of de bibliotheek babel.
String-methodes
Strings zijn onveranderlijk: een methode verandert de string niet, maar geeft een nieuwe terug. Je moet het resultaat dus opslaan.
naam = " Sam de Vries "
naam.strip()
print(f"[{naam}]")
naam = naam.strip()
print(f"[{naam}]")
[ Sam de Vries ]
[Sam de Vries]
De methodes die je het vaakst nodig hebt:
s = "Hallo, Wereld"
print(s.lower(), s.upper(), s.title())
print(s.startswith("Hal"), s.endswith("!"))
print(s.find("Wereld"), s.find("Mars"))
print(s.replace("Wereld", "Python"))
print(s.count("l"))
hallo, wereld HALLO, WERELD Hallo, Wereld
True False
7 -1
Hallo, Python
3
find geeft de positie, of -1 als het niet gevonden wordt. Wil je alleen weten óf iets erin staat, gebruik dan in: "Wereld" in s.
Splitsen en samenvoegen
split en join zijn elkaars tegenovergestelde:
regel = "2026-10-13;Utrecht;14.5"
datum, stad, temp = regel.split(";")
print(stad, float(temp) + 1)
woorden = ["een", "beetje", "coderen"]
print(" ".join(woorden))
print("-".join(woorden))
Utrecht 15.5
een beetje coderen
een-beetje-coderen
split() zonder argument splitst op elke reeks witruimte en negeert witruimte aan het begin en eind:
print(" twee spaties ".split())
print(" twee spaties ".split(" "))
['twee', 'spaties']
['', '', 'twee', '', '', 'spaties', '', '']
Let op: join is een methode van het scheidingsteken, niet van de lijst. En alle elementen moeten strings zijn: ", ".join([1, 2]) geeft een TypeError. Gebruik dan ", ".join(str(x) for x in getallen).
Uitgewerkt voorbeeld: namen opschonen
Uit een formulier komt een lijst namen, slordig ingevuld. Voorspel de uitvoer voordat je verder leest.
invoer = [" sam DE vries", "NOOR jansen ", "ali", ""]
namen = []
for ruw in invoer:
schoon = " ".join(ruw.split()).title()
if schoon:
namen.append(schoon)
for nr, naam in enumerate(namen, start=1):
print(f"{nr:>2}. {naam:<15}|")
1. Sam De Vries |
2. Noor Jansen |
3. Ali |
" ".join(ruw.split())haalt alle dubbele spaties en de spaties aan de randen weg.title()maakt van elk woord een hoofdletter, ook van "de". Dat is in Nederlandse namen niet altijd goed; netjes oplossen vraagt meer werk.- De lege string is "falsy" (
if schoonis onwaar) en wordt overgeslagen.
Encodings: tekst als bytes
Een computer slaat geen letters op, maar bytes. Een encoding bepaalt hoe tekens in bytes worden omgezet. De standaard is tegenwoordig UTF-8: gewone Engelse letters kosten één byte, andere tekens twee tot vier.
tekst = "café €5"
data = tekst.encode("utf-8")
print(data)
print(len(tekst), len(data))
print(data.decode("utf-8"))
b'caf\xc3\xa9 \xe2\x82\xac5'
7 10
café €5
é is twee bytes, € drie. Een str bevat tekens, een bytes-object (herkenbaar aan de b ervoor) bevat bytes. Van tekst naar bytes is encode, terug is decode.
Gaat het mis, dan krijg je onleesbare tekens of een fout:
data = "café".encode("utf-8")
print(data.decode("latin-1"))
print(data.decode("ascii"))
café
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 3: ordinal not in range(128)
café herken je vaak in de praktijk: UTF-8-bytes die als Latin-1 gelezen zijn. Geef bij het openen van bestanden daarom altijd de encoding op (meer in les 4):
with open("namen.txt", encoding="utf-8") as f:
...
Zonder encoding gebruikt Python de standaard van je besturingssysteem, en die is op Windows soms nog niet UTF-8. Hetzelfde programma kan dan op de ene computer werken en op de andere niet.
Veelgemaakte fouten
- Het resultaat van een methode niet opslaan:
naam.strip()in plaats vannaam = naam.strip(). joinaanroepen op de lijst:woorden.join(" ")geeftAttributeError: 'list' object has no attribute 'join'.- Getallen in een string optellen:
"3" + "4"is"34". Zet eerst om metint()offloat(). - Bestanden openen zonder
encoding="utf-8".
Oefenen
Oefening 1. Print voor de bedragen [3.5, 120, 0.99] een kolom met een euroteken, rechts uitgelijnd op 8 tekens met 2 decimalen, zoals € 3.50.
Modelantwoord oefening 1
for bedrag in [3.5, 120, 0.99]:
print(f"€{bedrag:>8.2f}")
€ 3.50
€ 120.00
€ 0.99
Oefening 2. Schrijf een functie initialen(naam) die van "sam de vries" de string "S.D.V." maakt.
Modelantwoord oefening 2
def initialen(naam):
return "".join(woord[0].upper() + "." for woord in naam.split())
print(initialen("sam de vries"))
print(initialen(" Noor Jansen "))
S.D.V.
N.J.
Oefening 3. Een bestand bevat de bytes b'Gr\xc3\xbcezi'. Hoe maak je er tekst van, en wat komt eruit?
Modelantwoord oefening 3
print(b'Gr\xc3\xbcezi'.decode("utf-8"))
Grüezi
\xc3\xbc is de UTF-8-codering van ü.
Lab: een rapport netjes uitlijnen
- In
rapport.pystaat een lijst met verkoopcijfers per medewerker (naam, aantal, omzet), slordig ingevoerd: namen met extra spaties en verkeerde hoofdletters. - Schrijf de functie
maak_rapport(regels)die een string teruggeeft met een tabel: de naam links uitgelijnd op 15 tekens, het aantal rechts op 5, de omzet rechts op 10 met 2 decimalen. - Voeg onderaan een regel
Totaaltoe met de som van het aantal en de omzet. - Lees ook
namen_latin1.txtin: dat bestand is opgeslagen als Latin-1. Zorg datMüllerenØrstedgoed worden weergegeven. - Controleer met
beetje check python-les3.
Samenvatting
- Formaatcodes in f-strings:
:.2f,:,,:.1%,:05d, uitlijnen met<,>en^plus een breedte;{x=}voor debuggen. - Strings zijn onveranderlijk: sla het resultaat van een methode op.
strip,lower/upper/title,replace,find,startswith,splitenjoinzijn je dagelijkse gereedschap.- Tekst (
str) wordt bytes (bytes) via een encoding; gebruik UTF-8 en geefencoding="utf-8"altijd op bij bestanden.
In les 4 werk je met bestanden en paden met pathlib.
Lab
Een rommelige namenlijst opschonen
💻 Dit lab doe je op je eigen computer met Docker. Start de lab-container met (geeft de opdracht een eigen startcommando, gebruik dan dat):
$ docker run -it --rm registry.wizg.it/webhosting/beetje-labs:python-les3
Klaar? Controleer je werk met:
$ beetje check python-les3