Naar de inhoud
maarten.
Alle stories

Unicode en tekencodering: tekstproblemen oplossen

Maarten Soetens 12 min lezen

Onleesbare tekens in een bestand, API of database ontstaan vaak doordat systemen tekst met verschillende tekencoderingen interpreteren. Lees hoe Unicode, UTF-8 en normalisatie werken en waar je bij gegevensuitwisseling op moet letten om tekstverlies en vergelijkingsproblemen te voorkomen.

Unicode en tekencodering zijn verschillende lagen

Unicode wijst aan ieder teken, symbool of bijvoorbeeld emoji een eigen codepunt toe, bijvoorbeeld U+0041 voor de hoofdletter A of U+20AC voor het euroteken. Dat codepunt zegt: dit bedoel je, maar het bepaalt nog niet hoe dit als bytes vastligt. Daar komt tekencodering in beeld. Met UTF-8 of UTF-16 zet je die codepunten om naar bytes, en andersom haal je er weer tekst uit.

Dat verschil, tussen bedoelde teken en daadwerkelijke bytevoorstelling, is een bron van veel tekstproblemen. Een app kan goede bytes ontvangen, maar leest ze verkeerd uit als er een andere codering was verwacht. Of data belandt netjes in geheugen maar wordt bij export teruggezet naar een ouder tekensysteem, waardoor speciale tekens verloren gaan. Je ziet dan vreemde tekst, terwijl de fout vaak zit in omzetting of interpretatie.

Kijk bij koppelingen dus niet alleen naar de tekens zelf, maar stel vast welke codering elk systeem gebruikt en verwacht. Ieder onderdeel kan daarvoor eigen instellingen hanteren: bron, app, database, bestandsformaat. Als dat nergens goed geregeld is, gaat het op aannames en oude defaults. Dat maakt sommige fouten lastig te reproduceren, met mogelijk verlies van tekens als gevolg.

UTF-8 opslaan en uitwisselen zonder aannames

In UTF-8 krijgt een Unicode-codepunt een tot vier bytes. Standaardletters en -cijfers vallen samen met ASCII, maar alles daarbuiten (denk aan een euroteken) vraagt extra bytes. Hierdoor is UTF-8 inzetbaar voor internationale tekst, zelfs in oude systemen die alleen ASCII kennen. Wees je ervan bewust: het aantal bytes is niet gelijk aan het aantal zichtbare tekens.

Veel moderne toepassingen kiezen standaard voor UTF-8, en met reden. Maar je moet afspreken: beide kanten lezen en schrijven in diezelfde codering. In bestanden kan het via doc, instellingen of de importoptie. Bij webverkeer gebruik jij (en de andere kant) headers, of het formaat zelf definieert het. Als je op de editor, runtime of server vertrouwt zonder te kijken, kan het resultaat per omgeving verschillen.

Dan de BOM, of byte order mark. In UTF-8 hoeft dat niet, want bytevolgorde is al vastgelegd. Toch voegen sommige programma’s die markering toe. Anderen zien die bytes als deel van de tekst, of negeren ze niet. Dus: stem gebruik van BOM af op wat de ontvanger verwacht, en test precies zo’n bestand in de beoogde software. Let bij valideren scherp op het onderscheid tussen bytes, codepunten en wat iemand als ‘een teken’ ziet. Een zichtbaar teken kan uit meer dan één codepunt bestaan.

Mojibake herkennen en de oorzaak terugvinden

Mojibake slaat op tekst die eruitziet als een rommelige mix van onleesbare tekens, meestal doordat bytes worden gelezen met een verkeerde codering. Vaak zie je dan gekke karakters op plekken van accenten of symbolen: denk aan "é" in plaats van "é". Zoiets gebeurt als iemand UTF-8 als Windows-1252 opent. Omgekeerd levert lezen van beperkte coderingen als UTF-8 soms dezelfde chaos op. Kijken naar de tekst zelf zegt niet altijd wat er precies misging.

Wil je weten waar het spaak loopt? Loop na: wat zijn de bytes aan de bron, na overdracht, en uiteindelijk na opslag? Zijn ze ergens anders geïnterpreteerd of veranderd, kun je dat niet meer moeiteloos rechtzetten. Zie je het karakter U+FFFD (vervangingssymbool) terugkomen? Die krijg je vaak als de decoder een bytevolgorde niet begrijpt. Helaas: als je daarna over de kapotte tekst heen hebt geschreven, is herstel meestal lastig.

Ga niet zomaar allemaal omzettingen toepassen tot iets er weer ‘klopt’. Daarmee repareer je het ene, maar maak je elders schade. Zorg altijd voor een archief van de originele bytes, achterhaal van de bron met welke codering je werkt. Test je fix met data die zeker accenten, valuta en bijzondere symbolen bevat. Leg daarna vast bij welke stap het probleem ontstond, zodat het niet telkens opnieuw verschijnt.

Unicode-normalisatie en tekst die gelijk lijkt

Je kunt hetzelfde teken in Unicode soms op meerdere manieren opslaan. Een letter met accent kan een enkel teken zijn, of een basisteken plus los accentaanduiding. Voor het oog gelijk, maar als codepunten en bytes verschillen ze. Dat kan problemen geven bij zoeken, unieke sleutels, of vergelijkingen van tekst.

Normalisatie maakt zulke verschillen gelijker, door volgens vaste regels verschillende varianten te uniformeren. NFC zoekt naar samengestelde tekens, NFD splitst ze juist uit. NFKC en NFKD voeren ook compatibiliteitsomzettingen uit; die vervangen bijvoorbeeld typografische of alternatieve varianten, soms ongewenst voor jouw toepassing. Dus: kies altijd de normalisatie die aansluit bij je gebruik.

Ga je teksten vergelijken, data importeren uit systemen, of zoekvelden aanbieden? Maak expliciet welke normalisatie je toepast en wanneer: liever bij invoer of vóór indexering dan ergens halverwege. Houd datasets consequent: als je maar een deel normaliseert, werken bestaande koppelingen of sleutels mogelijk niet meer. Voor situaties waar exacte bronweergave belangrijk is, bewaar altijd ook de invoer. Normalisatie helpt tegen weergaveverschillen, maar verandert niks aan betekenis, hoofdlettergebruik of interpunctie.

Tekencodering vastleggen in bestanden en webverkeer

Een txt- of csv-bestand laat meestal niet zien welke codering het gebruikt, en programma’s als Excel kiezen soms zelf een standaard. Daardoor lijkt het bestand bij de bron goed en aan de ontvangende kant ineens defect. Dus: leg bij uitwisseling altijd vast welke codering je bedoelt, stem import en export daarop af. Aanname dat de ander UTF-8 gebruikt, leidt vaak tot fouten, test gewoon met voorbeelddata waarin speciale tekens voorkomen.

Bij HTTP-verkeer sturen headers en het gebruikte mediatype mee hoe je de inhoud moet lezen. JSON is normaal gesproken UTF-8, andere soorten kunnen charsets in de header verwachten. Kijk niet alleen naar de headers: als daar UTF-8 staat maar de data anders is gecodeerd, blijft het stuk. Idem andersom: alleen UTF-8 instellen bij ontvangst helpt niet als de zender iets anders heeft gedaan.

Check samengestelde documenten. HTML kan zijn codering declareren, maar proxies, sjablonen en exportlagen voegen soms nog eigen bewerkingen toe. CSV-bestanden leveren vaak hun eigen problemen op: scheidingstekens, quote-karakters of regeleinden kunnen naast de tekencodering verwarring veroorzaken. Documenteer zowel bestandsformaat als codering bij overdracht, en test volledige exports met de software die de data straks echt moet lezen.

Databasekolommen, verbindingen en collaties controleren

Fouten met tekst ontstaan in databases op allerlei plekken: definities van kolommen, gebruikte verbindingen, of de client die uitleest. Dus: zelfs als een kolom Unicode ondersteunt, kan het mislopen als de verbinding daar niet op is afgestemd. Verschillen bestaan niet alleen tussen producten (MySQL, Postgres, SQL Server) maar ook per versie, in naamgeving en dekkingsgraad van tekensets. Kijk daarom altijd naar encoding op database-, tabel-, kolom- én verbindingsniveau.

Beperkingen in tekenset kunnen invoer weigeren, vervangen of stilzwijgend omzetten. Die aanpak hangt van de instellingen en SQL-modi af. Dat een insert slaagt betekent dus niet per se dat elk teken ongewijzigd blijft. Test opslaan en uitlezen via dezelfde route en vergelijk indien nodig de ruwe data. Probeer niet alleen gewone letters: ook emoji en niet-Latijnse tekens zijn nuttig om echt uit te sluiten dat je niks kwijt raakt.

Collaties regelen meer: ze bepalen jouw sortering en vergelijken, bijvoorbeeld hoe accenten of hoofdletters worden behandeld. Twee kolommen met dezelfde tekens kunnen daardoor verschillend sorteren of matchen. Bij migraties beïnvloedt veranderen van collatie of tekenset bestaande unieke indexen. Controleer dus niet alleen de opslag, maar ook het gedrag bij vergelijken en zoek bij aanpassingen altijd naar afwijkingen aan de hand van echte testdata, inclusief gevallen met botsende sleutels.

Unicode behouden door API’s en gegevenspijplijnen

In een API moet niet alleen staan waar tekst komt, maar ook hoe die tekst gecodeerd en gevalideerd wordt. In JSON mag je Unicode gewoon direct schrijven of in escapes zetten. Beide zijn goed, zolang de parser correct werkt. Problemen ontstaan als een tussenlaag de bytes opnieuw decodeert, een lib een andere standaard pakt, of het bericht stiekem als andere tekenset oppakt.

Loop bij een pijplijn de tekst na elke stap na: ophalen, parsen, valideren, opslaan, loggen, exporteren. Soms zit de fout in een queue-consumer; soms pas bij export naar een CSV. Zet de afspraken over codering en validatie vast op elke grens, en laat de decoder problemen met ongeldige bytes signaleren. Stiekem vervangen is niet altijd handig: je merkt dan pas laat dat tekst veranderd is.

Verwar escaping niet met tekencodering: JSON-escaping beschermt de structuur, verandert de betekenis van tekens niet. HTML-escaping voorkomt interpretatie als markup, beschermt niet tegen verkeerde UTF-8. Houd die functies uit elkaar in code en tests. Loggen van foute tekst? Sla bron, record-ID en stap op; deel niet onnodig gevoelige tekst in logs. Zo blijf je achteraf terugvinden waar het misging zonder nieuwe risico’s te introduceren.

Zoeken, vergelijken en sorteren met Unicode-tekst

Vergelijkingen van strings werken niet automatisch zoals mensen woorden als gelijk zien; normalisatie, case, accenten en combinatietekens brengen aanvullende verschillen mee. Wat je wilt bereiken bepaalt hoe je vergelijkt: voor identificatie stel je strengere eisen dan bij zoeken waarbij typografische variaties geen belemmering mogen zijn. Maak hierin bewuste keuzes, want tekst zonder context vergelijken is nooit één-op-één.

Zoeken, sorteren en indexeren gaat in zoekmachines en databases lang niet altijd hetzelfde. Als je indexeert op NFC, maar invoer in een andere vorm komt, mis je soms hits. Een collatie die accenten negeert levert meer matches op, maar kan onderscheid tussen namen doen verdwijnen. Test met echte data uit de belangrijkste talen en kijk goed naar index én query. Als je normalisatie toepast, doe dat altijd op de invoer én index, nooit op slechts één zijde.

Let op: codepunten zijn wat anders dan wat mensen als een ‘teken’ zien. Samengestelde emoji’s kunnen uit meerdere codepunten bestaan. Trim je bijvoorbeeld op codepuntlengte, kan een halve emoji overblijven. Voor limieten in een UI kijk je naar grafemen (wat je ziet), bij opslag gaat het om bytes. Wees daar duidelijk over in documentatie en test op afkapping, sortering en unieke waarden met samengestelde tekens.

Tekencoderingsfouten testen, monitoren en veilig verwerken

Een goede testset voor tekst bevat niet alleen a-z, maar zeker ook accenten (in samengesteld en ontleed formaat), niet-Latijnse karakters, leestekens, valuta, emoji’s. Neem geldige én opzettelijk ongeldige bytevolgorden op: zo zie je per laag wat er met slechte invoer gebeurt. Alleen kijken of een bestand opent is onvoldoende; je mist dan geruisloze vervanging of afkapping die pas na export opvalt.

Vergelijk bij tests niet alleen de zichtbare tekst, maar controleer codepunten of bytes rond gevoelige grensvlakken. Voer roundtrips uit: coderen, transporteren, decoderen, en de uitkomst naast de invoer leggen. Zitten er lege velden, te lange zinnen of verborgen tekens in? Juist die catch je hier. Met migraties is voor- en nacontrole een must: anders merk je pas te laat dat er iets kwijt is geraakt, of oude waardes nu conflicteren.

Onzichtbare tekens zoals richtingstekens of nulbreedte-karakters verdienen aparte aandacht. Soms essentieel voor correcte weergave (Arabisch, Indic), soms gebruikt voor verwarring of misleiding. Keer dus niet standaard onbekende codes uit een string. Maak diagnosehulpmiddelen waarmee deze tekens zichtbaar worden en beperk toegang tot ruwe dumps. Alleen zo krijg je fout oorzaken scherp zonder data onnodig te filteren.

Veelgestelde vragen

Waarom telt een emoji soms als meerdere tekens in programmeercode?

Een emoji kan opgebouwd zijn uit meerdere Unicode-codepunten die samen één zichtbaar teken vormen. Dus een familiegroep, huidtint of vlag bestaat technisch uit een reeks, niet uit slechts één codepunt. Een functie die codepunten of bytes telt, komt daardoor (vooral bij samengestelde emoji’s) uit op meer dan je visueel verwacht.

  • Gebruik functies die grafemen herkennen voor tellen, selectie en cursorpositie.
  • Test invoervelden en limieten met samengestelde emoji’s in plaats van alleen standaardletters.
  • Controleer of afkappen niet midden in een samengestelde emoji gebeurt.

Hoe voorkom ik Unicode-homogliefaanvallen in gebruikersnamen?

Voorkomen doe je door op elkaar lijkende tekens uit verschillende schriften niet automatisch als veilig van elkaar verschillend te behandelen. Zo lijkt een Cyrillische a sterk op een Latijnse, maar technisch zijn ze niet hetzelfde. Een aanvaller kan daarmee een gebruikersnaam nabootsen en verwarring zaaien.

  • Sta alleen gewenste schriften toe bij gebruikersnamen als dat kan.
  • Waarschuw voor namen die nagenoeg hetzelfde eruitzien als bestaande accounts of domeinen.
  • Gebruik consequente vergelijkingsregels voor account-ID’s, maar bewaar ook altijd de exacte invoer.
  • Laat beheerders verdachte namen controleren en toon namen helder in interfaces.

Waarom verschijnt een Unicode-teken als een vierkantje of vraagteken?

Dat vierkantje betekent meestal: het gebruikte lettertype kent geen glyph voor dat karakter, zelfs als de tekst technisch correct is opgeslagen. Een vraagteken krijg je soms doordat een app het teken tijdens conversie of bij weergave heeft vervangen. Dit zegt niet automatisch iets over codering: opslag, verwerking en weergave zijn losse fasen.

  • Kijk of hetzelfde bestand met een ander programma of lettertype wél juiste tekens toont.
  • Controleer opgeslagen waarde: was het teken al vervangen voor opslag?
  • Gebruik lettertypes die nodig schriftsoorten en symbolen aankunnen.
  • Test interfaces op apparaten en systemen die jouw gebruikers hebben.

Waarom wordt tekst afgekapt als een databasekolom genoeg tekens lijkt toe te staan?

Vaak ligt dat aan het verschil tussen limieten in bytes, codepunten, of zichtbare tekens. In UTF-8 zijn veel tekens meer dan één byte, en een zichtbaar teken kan zelfs uit meerdere codepunten bestaan. Dus wie alleen een bytebudget hanteert, stuit soms eerder op de grens dan je op basis van lettertelling verwacht.

  • Kijk in documentatie: is de limiet bytes, codepunten of echte tekens?
  • Check ook limieten in formulieren en API-validatie; de krapste limiet bepaalt de opslag.
  • Test met lange velden, accenten, niet-Latijnse tekens en emoji’s rond die limiet.
  • Geef gebruikers een duidelijke foutmelding, kap niet stilletjes af.

Waarom staat leestekens soms aan de verkeerde kant van Arabische of Hebreeuwse tekst?

Dat zie je doordat je een rechts-naar-links-schrift combineert met links-naar-rechts-tekst zoals cijfers, adressen of Latijnse woorden. Unicode gebruikt algoritmen die de visuele volgorde bepalen; de interne opmaak en visuele weergave hoeven niet gelijk te zijn.

  • Zet tekstoriëntatie in de UI expliciet waar je die context weet.
  • Gebruik voor stukken met een ander schrift richtingsinstellingen, bijvoorbeeld HTML-attributen.
  • Test combinaties met cijfers, haakjes, URL’s en leestekens in Arabisch of Hebreeuws.
  • Verwijder richtingstekens niet zomaar, soms zijn ze hard nodig voor correcte weergave.
Portret van Maarten

Maarten

Freelance developer in Nijmegen

Even kennismaken?

Vertel kort wat er speelt. Dan hoor je wat er kan, wat ik anders zou doen en waar AI bij jou wél en niet iets toevoegt. Vrijblijvend.

[email protected]
Het kantoor in Nijmegen
© 2026 maarten.online Sitemap Privacy Algemene voorwaarden
Het kantoor in Nijmegen

Maarten.

Freelance developer in Nijmegen. Liever direct contact? Dat kan ook.

Kennismaken

Laat je gegevens achter, dan kijken we of het klikt. Vrijblijvend en zonder verkooppraat.

Maarten

Stuur een bericht via WhatsApp

Hoi! Waar kan ik je mee helpen?

nu