Tekencodering achterhalen
Welke tekencodering [2], of character encoding [3], character set of karakterset wordt er gebruikt voor een bepaald tekstdocument? Waar moet ik rekening mee houden bij exporteren of uitwisselen van gegevens?
Tekens & codering
Handig bij debuggen:
Teken Latin1 UTF8 Opmerkingen ----- ------ ---- ------------------------- 1 31 31 € 80 e2 82 ac ű 3f c5 b1 ` 60 60 “ 93 e2 80 9c Linker aanhalingstekens ” 94 e2 80 9d Rechter aanhalingstekens
Gegenereerd in MySQL met zoiets als:
select convert(convert("€" using utf8) using binary) as bin_utf8, convert(convert("€" using latin1) using binary) as bin_latin1; select convert(convert("“" using utf8) using binary) as bin_utf8, convert(convert("“" using latin1) using binary) as bin_latin1; select convert(convert("”" using utf8) using binary) as bin_utf8, convert(convert("”" using latin1) using binary) as bin_latin1;
Detectie - VIm
Met VIm lijk je prima bestandscoderingen te kunnen achterhalen. Bv.:
Bestand openen :set fileencoding
Let op
- Gebruik
set fileencoding
en nietset encoding
- Met dit eerste commando leest-ie de bestaande codering. Met het tweede commando doet-ie iets anders ofzo - Dit werkt alleen als een bestand gebruik maakt van maar één karakterset.
Detectie - Hexdump
Met de standaard Bash-routine hexdump kun je prima tekstcoderingen achterhalen - als je weet waar je moet zoeken! Zie de voorbeelden verderop in dit artikel.
Test: "€"
MySQL
Twee bestanden zijn gegenereerd in MySQL, met daarin alleen een "€"-teken, respectievelijk in latin1 en utf8:
select convert("€" using latin1) into outfile "/tmp/1008-latin1.txt"; select convert("€" using utf8) into outfile "/tmp/1008-utf8.txt";
Hexdump
Afgekort (ook op Bash): hd
>> hexdump 1008-latin1.txt 0000000 0a80 0000002 >> hexdump 1008-utf8.txt 0000000 82e2 0aac 0000004
Hier is de eerste kolom de offset. Zonder offset zou de output zijn:
0a80 82e2 0aac
Je kunt hieraan zien dat de bestandscodering little endian is. Als het big endian zou zijn geweest:
80 0a e2 82 ac 0a
En 0a is LF (linefeed) - De standaardcode voor een newline op Unix en Unix-achtige operaring systems (inclusief Linux en MacOS) [4]
Als ik het latin1-bestand open in Sublime Editor, en de newline verwijder + wegschrijf, krijg ik daarna met hexdump
>> hd 1008-latin1-verkort.txt 00000000 80 00000001
VIm
VIm lijkt zich te verslikken in Latin1:
set encoding
werkt niet:
set fileencoding
werkt wel:
Sublime Editor
Wat ik zoal in het wild tegenkom
fileencoding=latin1 iso-8859-1. 'Latin1' is de 1-subset van iso-8859. Dit is de standaard Microsoft-codering. Oa. in gebruik voor import Bol.com en Amazon fileencoding=utf-8 Standaard voor nieuwe tekstbestanden op Unix? fileencoding=utf-161e Export Google AdWords-editor
Meerdere karaktersets in één bestand
MySQL-exports willen zomaar meerdere coderingen in één export-bestand gebruiken, omdat je per kolom de karakterset kunt bepalen, en dat wil nogal eens gebeuren. Editors kunnen daar niet zondermeer mee overweg.
Probleem met linker- & rechter dubbele aanhalingstekens (93 & 94)
Alle tekenwaardes zijn gegeven in hex:
Het probleem
- Dit betreft een upload voor Amz.de in juli 2020
- Titels bevatten linker- & rechter dubbele aanhalingstekens zoals dit:
“BLAUBEERE”
- In latin1 (8859-1) zijn dit tekens 0x93 en 0x94
- In utf8 zijn dit
e2 80 9c
ene2 80 9d
(kies in MySQL zo'n veld → Open Value in Editor) - De export is ook in latin1 (zo wil Amz het blijkbaar graag hebben)
- Bij import in Calc, gaat dit mis. Een ä gaat trouwens wel goed:
ä BLAUBEERE
. Je kunt zien dat de tekens vermoedelijk zijn gecodeerd met één byte per karakter - Ook VIm weet tot m'n verbazing geen raad met deze tekens:
<93>BLAUBEERE<94>
, terwijl de filencoding wel latin1 is.
Oorzaak?
Geen idee. Misschien een lacune in de specificatie van 8859-1-latin1: Organisaties die op eigen houtje deze tekens hebben geïntroduceerd zonder dat deze officiëel ondersteund worden?
Oplossing
Simpel: Allemaal vervangen door rechte dubbele aanhalingstekens (0x22).
P.s.: Ik had een eerdere export met daarin hetzelfde probleem. Het bleek dat ik daar dezelfde oplossing had toegepast.