[Perl] UTF8 hash key downgraded when assigned

Gérald SÉDRATI-DINET gerald at sedrati-dinet.net
Sam 1 Déc 01:03:15 CET 2018


Salut les Mongueurs!

Ça faisait longtemps que je n'avais pas posté ici, mais maintenant que
j'ai la joie de retravailler en Perl, j'ai aussi celle de partager à
nouveau de vos lumières :)

Je suis tombé sur un étrange comportement, sur toutes les versions de
Perl que j'ai pu testées (entre la 5.16 et la 5.26).

Il y a une question sur stack overflow
(https://stackoverflow.com/questions/8418496/hash-keys-encoding-why-do-i-get-here-with-develpeekdump-two-different-resul)
qui date de quelques années mais sans réponse s'il s'agit ou non d'un
bug d'optimisation ou d'un comportement normal.

Le problème et que si vous initialisez un hash avec une clé ayant des
caractères non-ascii (par ex. du iso-8859-1), la clé est correctement
encodée en UTF8 (avec le flag UTF8 positionné). Mais si vous assignez
ensuite une valeur à l'élément du hash correspondant à cette clé,
celle-ci est déclassée (comme avec un utf8::downgrade, probablement
encodée en iso-8859-1). Je vous laisse imaginer les conséquences si vous
avez à manipuler cette clé pour une raison ou pour une autre, en vous
attendant à ce qu'elle soit encodée en  UTF8…

Voilà un script montrant le problème:

#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use Devel::Peek;
use Data::Dumper;
$Data::Dumper::Useqq = 1;

my %hash = (
    'clé' => 0,
);
my $key = (keys %hash)[0];
Dump($key);
print Dumper($key);

$hash{'clé'} = 1;
$key = (keys %hash)[0];

Dump($key);
print Dumper($key);

utf8::upgrade($key);
Dump($key);
print Dumper($key);
[download]

avec le résultat suivant:

SV = PV(0x555ed17dfe60) at 0x555ed1809710
  REFCNT = 1
  FLAGS = (POK,pPOK,UTF8)
  PV = 0x555ed1993ed0 "cl\303\251"\0 [UTF8 "cl\x{e9}"]
  CUR = 4
  LEN = 5
$VAR1 = "cl\x{e9}";
SV = PV(0x555ed17dfe60) at 0x555ed1809710
  REFCNT = 1
  FLAGS = (POK,IsCOW,pPOK)
  PV = 0x555ed1909b10 "cl\351"
  CUR = 3
  LEN = 0
$VAR1 = "cl\351";
SV = PV(0x555ed17dfe60) at 0x555ed1809710
  REFCNT = 1
  FLAGS = (POK,pPOK,UTF8)
  PV = 0x555ed1825350 "cl\303\251"\0 [UTF8 "cl\x{e9}"]
  CUR = 4
  LEN = 10
$VAR1 = "cl\x{e9}";
[download]

Comme dans ce code, on peut résoudre le problème en surclassant en UTF8
(utf8::upgrade) la clé. Mais j'aurais jamais imaginé devoir faire ça
avant de tomber sur le problème. J'ai rien lu dans perldoc qui explique
ce comportement.

Vous avez une idée d'explication, si c'est ou non voulu ?

Merci!
-- 
Gérald Sédrati-Dinet
https://pascontent.sedrati-dinet.net     https://www.april.org
https://www.unitary-patent.eu            https://laquadrature.net

-------------- section suivante --------------
Une pièce jointe autre que texte a été nettoyée...
Nom: signature.asc
Type: application/pgp-signature
Taille: 195 octets
Desc: OpenPGP digital signature
URL: <http://listes.mongueurs.net/archives/perl/attachments/20181201/e35417db/attachment-0001.bin>


Plus d'informations sur la liste de diffusion Perl