- Kotlin + Brainfuck : efficacité, compacité, optimisation
- Comment résoudre un problème d'informatique
Ah, Ruby…
Ruby et sa merveilleuse idée d’avoir une unique classe pour représenter tous les types de chaînes (brutes comme encodées), de tous les encodages (UTF-8, UTF-16, latin-1, etc.), à savoir String
.
Oui, en Ruby, deux instances de String
peuvent avoir des encodages différents. Des types non compatibles entre-eux, mais instances d’une même classe, et seulement différenciés par leur attribut encoding
.
1 2 3 4 5 6 7 8 | irb> utf8_str = 'âbc' => "âbc" irb> latin1_str = 'âbc'.encode('iso-8859-1') => "\xE2bc" irb> utf8_str.encoding => #<Encoding:UTF-8> irb> latin1_str.encoding => #<Encoding:ISO-8859-1> |
Enfin, quand je dis non compatibles, ce serait encore assez logique, mais c’est plus fourbe que ça !
Parfois compatibles, parfois pas.
Ruby choisit de ne planter que le plus tard possible, donc si les caractères des deux chaînes n’entrent pas en conflit, tout se passe bien.
Petit exemple avec la concaténation d’une chaîne UTF-8 avec une latin-1.
1 2 3 4 5 6 7 8 9 10 | irb> 'abc' + 'abc'.encode('iso-8859-1') # Là c'est ok => "abcabc" irb> 'âbc' + 'abc'.encode('iso-8859-1') # Là aussi => "âbcabc" irb> 'abc' + 'âbc'.encode('iso-8859-1') # Toujours ok => "abc\xE2bc" # Ouais, dans un cas ça retourne une chaîne UTF-8, dans l'autre une latin-1, yolo irb> 'âbc' + 'âbc'.encode('iso-8859-1') # Là ça casse tout Encoding::CompatibilityError: incompatible character encodings: UTF-8 and ISO-8859-1 from (irb):5 from /usr/bin/irb:11:in `<main>' |
Mais s’il n’y avait que ça…
On a aussi en Ruby la possibilité de créer des chaînes de caractères invalides. En effet, Ruby ne plantera pas lors de la création d’une chaîne invalide, mais seulement lors de l’exécution de certaines opérations (pas toutes, faut pas rigoler).
1 2 3 4 5 6 7 8 9 10 11 | irb> invalid_str = "\xE9" => "\xE9" irb> invalid_str.valid_encoding? # Il sait qu'elle est invalide => false irb> invalid_str + '!' # Mais ça n'a pas l'air de trop le gêner => "\xE9!" irb> invalid_str.gsub('', '') # Ah ben si, un peu quand même ArgumentError: invalid byte sequence in UTF-8 from (irb):22:in `gsub' from (irb):22 from /usr/bin/irb:11:in `<main>' |
On croirait presque que le langage nous incite à créer des chaînes invalides, quand on voit que la classe String
comporte une méthode force_encoding
.
Cette dernière permet tout simplement de redéfinir l’encodage d’une chaîne, sans pour autant la réencoder.
1 2 3 4 5 6 7 8 | irb> latin1_str = 'ça pue'.encode('iso-8859-1') => "\xE7a pue" irb> latin1_str.valid_encoding? # Elle est pour l'instant valide => true irb> latin1_str.force_encoding('utf-8') # Et hop, UTF-8 ! => "\xE7a pue" irb> latin1_str.valid_encoding? # Tant pis :/ => false |
Je n’ai pas fait le tour de tous les langages existant, mais on ne doit pas être loin d’avoir là une des pires implémentations de l’Unicode et des multiples encodages.
Rendez-moi Python
Alors, convaincus ?