Tekencodering achterhalen

Uit De Vliegende Brigade
Naar navigatie springen Naar zoeken springen

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 niet set 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:

VIm kan het bestand niet zondermeer lezen. Het wordt gecodeerd en ipv. het euroteken, wordt de hexwaarde weergegeven. Daarnaast heeft VIm de informatie geconverteerd (in het geheugen, niet op schijf!)

set encoding werkt niet:

Latin1: Bestandscodering wordt gegeven als utf8 - Dat klopt niet

set fileencoding werkt wel:

Latin1: Geen probleem
UTF8: Geen probleem

Sublime Editor

Latin1: Geen probleem
UTF8: Geen probleem
Ook interessant: Het bestand bevat twee karakters: Naast "€" een CR, LF of beide

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.

In dit voorbeeld met Sublime Editor, zijn er twee €-tekens. Het eerste is weergegeven in Latin1, het tweede in UTF-8. Blijkbaar kiest Sublime voor Latin1. Lijkt me logisch, want dat is het eerste teken
Hetzelfde bestand, maar nu geopend als UTF-8-bestand. Ik geloof dat UTF-8 geen code '80' kent [1] - Vandaar het vraagteken?

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 en e2 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.

Zie ook

Bronnen