
Hex-teksti teisendus läks valesti: kodeerimisvead, mis muudavad baidid jamaks
Avaldatud 24. juuli 2026
Hexi teksiks teisendamine peaks tunduma eksimatu: iga hex-numbripaar on üks bait, mapid baidi märgiks ja ongi valmis. Praktikas ebaõnnestub see pidevalt ja peaaegu mitte kunagi sellepärast, et teisendaja oleks katki — see ebaõnnestub, sest hex on lihtsalt viis baitide kirjapanekuks ning baidid vajavad kokkulepitud kodeeringut, enne kui nad üldse mingit kindlat märki tähendavad. Siin on, mis tegelikult valesti läheb, kui väljund on moondunud.
Põhjus 1: valesti eeldatud märgikodeering
Kõige levinum põhjus. Hex-baidid kodeeriti UTF-8 vormingus (kus paljud päris maailma märgid võtavad 2–4 baiti), aga teisendaja dekodeerib baidi kaupa, justkui oleks tegemist Latin-1 või tavalise ASCII-ga (kus iga bait on täpselt üks märk). Tulemus: rõhumärkidega tähed, kaarjutud jutumärgid, pikad mõttekriipsud või mistahes mitteingliskeelne märk muutuvad kahest-kolmest moondunud sümbolist koosnevaks jamaks ühe õige märgi asemel.
Lahendus on alati dekodeerida sama kodeeringuga, milles baidid algselt kirjutati — kui sa ei tea, milline see oli, on UTF-8 õige vaikevalik kõige jaoks, mis on tänapäevane (veebisisu, JSON, enamik API-sid); Latin-1/Windows-1252 esineb enamasti vaid vanemates Windowsi päritolu tekstifailides või pärandmeili päistes.
Põhjus 2: baidijärjekorra (endianness) mittevastavus
See mõjutab konkreetselt mitmebaidiseid arvväärtusi (mitte teksti), aga see on piisavalt levinud hex-teksti tööriistades, mis käsitlevad segatud binaar-/tekstiandmeid, et seda mainida tasub. 00 01 big-endian lugemisel on 1; samad kaks baiti little-endian lugemisel on 256. Kui hex-string esindab arvulist pikkuse eesliidet või binaarvälja, mis on põimitud muidu tekstilisse andmesse, siis vale baidijärjekorraga lugemine ei loe mitte ainult arvu valesti — see nihutab iga järgneva baidi asukohta, sest tööriist arvab nüüd, et tekst algab vales kohas.
Põhjus 3: nibli rühmitusvead
Hex peaks alati tulema paarikaupa — kaks hex-numbrimärki moodustavad ühe baidi. Paaritu arv hex-märke (üks eksinud number, kopeeri-kleebi käigus kadunud märk, algne 0x, mida enne parsimist ei eemaldatud) nihutab iga järgneva paari ühe nibli võrra. Iga bait pärast viga dekodeerub täiesti erinevaks, seosetuks märgiks — väljund pole “veidi vale”, see on sellest kohast alates täielikult segamini, mis on tegelikult kasulik diagnostika: jama, mis algab puhtalt ja rikneb kuskil keset stringi, viitab rühmitusveale täpselt selles kohas, mitte vale kodeeringu probleemile (mis rikub kogu teksti ühtlasemalt).
Põhjus 4: nähtamatud ja mitteprinditavad baidid
Mitte iga bait ei mapi nähtavale märgile. Juhtmärgid (0x00–0x1F), baidijärjekorra märgis (EF BB BF UTF-8-s) ja mitmesugused Unicode vormindusmärgid dekodeeruvad “edukalt”, aga kuvatakse mittemidagi, kastina või küsimärgina sõltuvalt kuvafondist — mis võib näha välja identne dekodeerimisveaga, kuigi teisendus ise oli täiesti õige. Kui väljundi pikkus tundub õige, aga tekstis paistavad märgid puuduvat, kontrolli juhtbaite, enne kui eeldad, et dekodeerimisloogika on vale.
Kiire viis tuvastada, millega tegu on
- Kinnita, et hex-stringis on paarisarv märke — kui mitte, on see põhjus 3, paranda kõigepealt sisend.
- Proovi dekodeerida esmalt UTF-8-na, seejärel Latin-1-na, ja võrdle — kui üks annab puhta teksti ja teine mitte, oli see põhjus 1.
- Kui väljund on ühtlaselt moondunud juba esimesest märgist alates, kahtlusta kodeeringut (põhjus 1); kui see algab puhtalt ja rikneb kuskil keskel, kahtlusta rühmitusviga (põhjus 3) selles kohas.
- Kui pikkus vastab ootustele, aga konkreetsed märgid puuduvad või kuvatakse kastidena, kontrolli juht-/vormindusbaite (põhjus 4), mitte kodeeringut uuesti üle.
Hex-teksti teisendus ise on igas keeles üks koodirida — tegelik silumistöö seisneb peaaegu alati selles, milline neist neljast eeldusest vaikimisi valesti oli, mitte teisendusloogikas endas.