Blog de développement

Encodage et UTF-8

Dernière Modification le :
2024-02-19

A lire absoluement https://www.invivoo.com/resoudre-vos-problemes-dencodage-unicode/ https://www.invivoo.com/en/how-to-solve-unicode-encoding-issues/

On butte sur un os... Quelques exemples...

utf8-debug est une page Web qui visualise les différentes substitutions d'encodage : Lire → (les autres pages sont dans l'archive)

Microsoft fournit une liste de référence des encodages Lire →

Cette page Web vous permet de tester différentes chaînes de caractères ou des fichiers et d'afficher leur représentation dans différents jeux de caractères et encodages, y compris UTF-8, ISO-8859-1, Windows-1252... freeformatter.com →

Dans le ZIP de ressources, j'ai mis un jeu de six fichiers texte qui représentent cinq codages de caractères différents et six langues différentes. Les encodages de caractères représentés dans ce jeu de données sont ISO-8859-1 (également connu sous le nom de Latin 1), ASCII, Windows 1251, UTF-16 qui a été converti avec succès en UTF-8 et BIG-5. De plus amples informations sur les fichiers sont disponibles dans le fichier file_guide.csv.

Plusieurs Codes Pages pour le prix d'un!

Il y a en fait plusieurs codes pages qui s'appliquent parfois à de vieux utilitaires. Le code page utilisé par la console (CMD) est 'CHANGE', CHCP

  • Page de Codes OEM (OEMCP) : age de codes utilisée par les applications console qui ne prennent pas en charge Unicode
  • Page de Codes ANSI (ACP) : La page de codes ANSI est utilisée par les applications Windows non Unicode.
  • Page de Codes Macintosh (MACCP) : était plus pertinente pour l'interaction entre Windows et Macintosh.
  • Page de Codes EBCDIC (EBCDICCP) : principalement dans les systèmes mainframe et pas couramment en Windows moderne

Sur les PC 'Desktop' c'est UTF-8, pour tous. Cependant, pour le serveur, c'est ... Un script peur donc avoir un comportement different selon qu'on est en desk ou sur le serveur !

CodePage Serveur DeskTop
CHCP 850 65001 (=UTF-8)
ACP 1252 65001 (=UTF-8)
OEMCP 850 65001 (=UTF-8)
MACCP
EBCDICCP
10000 65001 (=UTF-8)

On a le probleme avec ZIP (Windows) si on veut envoyer un dossier compressé sur un système Occidental ou moderne vers un Windows Asiatique un peu ancien... ou même avec 7-Zip (7-Zip ne permet pas explicitement de choisir un encodage autre qu'UTF-8 via la ligne de commande)

FSO FileSystemObject et tristate

L'option finale a 3 valeurs possibles (tristate...). La valeur 0 encode en ASCII, quel que soit le PC.

FSO Serveur DeskTop
-1 Unicode donc UTF-16 LE Unicode donc UTF-16 LE
-2 CP850 65001 (=UTF-8)

Donc si on veut UFT-8 sur le serveur, il faut utiliser ADODB.STREAM à la place de FSO

Détection de l'encodage

L'outil populaire pour le faire à la main est NotePad++. LibreOffice, aussi...
Sur le serveur, on peut parfois utiliser ICONV. Mais peut-être pas toujours...

"C:\...\iconv.exe" -f ascii -t Windows-1252 "C:\...\yan_BIG-5.txt" 1> NUL 

répond iconv: C:\...\yan_BIG-5.txt: ne peut convertir

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("input.txt", 1)

If objFile.AtEndOfStream Then
    WScript.Echo "Le fichier est vide."
Else
    strLine = objFile.ReadLine
    If IsNull(strLine) Then
        WScript.Echo "Le fichier est binaire et ne peut pas être lu en texte."
    Else
        strEncoding = "Inconnu"
        If objFile.CodePage = 1252 Then
            strEncoding = "Windows-1252 (ANSI)"
        ElseIf objFile.CodePage = 65001 Then
            strEncoding = "UTF-8"
        End If
        WScript.Echo "L'encodage du fichier est : " & strEncoding
    End If
End If

objFile.Close
Set objFile = Nothing
Set objFSO = Nothing

Le

Tables de conversion

https://stackoverflow.com/questions/42250575/iconv-translit-table-of-characters

The table is defined in the file translit.def. You may find it inside the libiconv. The library might be download at: https://ftp.gnu.org/gnu/libiconv/. I've extracted the first few lines of the table, which are displayed bellow:

conversion de MS-DOS (= CP850, c'est le CodePage de mon serveur) à UTF-8 Lire →

Conversion par script avec ICONV

Quand on convertit avec ICONV, il faut capturer la sortie avec 1>, qui utilise l'encodage par défaut de la cession CMD. Il peut être nécessaire de forcer CMD à écrire dans l'encodage souhaité en ajoutant CHCP xxx en première ligne. C'est peut être utile voire nécessaire pour s'assurer qu'un fichier .CSV est bien au bon encodage avant d'utiliser BCP. C'est le cas sur mon serveur, vraiment vieillot!, qui est en CHCP 850 (MS-DOS Latin1),

La conversion est toujours partiellement possible. Les chiffres 'arabes' sont universels et ne posent pas de problèmes. Là où il y a potentiellement problème, il faut définir une stratégie a priori.

  • Substituer à 'notre mode' avec un script
  • Bloquer la conversion (avec... Rien, c'est à dire, par défaut)
  • Substituer à la mode 'ICONV' avec //TRANSLIT
  • Ignorer avec //IGNORE

GNUwin32 décrit les flags de son ICONV Lire →
La liste de translitération est accessible selon l'explication ici → . J'en mets une copie (.txt encodé en UTF-8) dans les ressources et en HTML (charset=utf-8 et balise pre): Lire →.
Chez moi, //TRANSLIT//IGNORE n'est pas supportée... On peut éventuellement instruire de faire des conversions à la demande, ce que, en pratique, je n'utilise pas.

Détecter la présence de caractères de substitution

Lors de la lecture ou écriture d'un Fichier UTF-8 (ou pas) avec ré-écriture qu'on pourrait penser satisfaisante, si vous avez une erreur de programmation ou de gestion d'encodage, des caractères de substitution peuvent apparaitre soit sous la forme de ? ou losange noir...

En pratique, en UTF-8, le seul et unique "caractère de substitution" est la séquence de caractères hexadécimaux EF BF BD (�). Il existe d'autres séquences importantes dans l'encodage UTF-8, notamment celles utilisées pour encoder des caractères spécifiques :
Byte Order Mark (BOM) : la séquence EF BB BF est utilisée comme marqueur d'ordre des octets (BOM) en UTF-8. Elle est optionnelle et généralement non recommandée pour les fichiers UTF-8, car l'ordre des octets n'est pas pertinent dans cet encodage.
Caractères de Contrôle : Il existe plusieurs séquences qui représentent des caractères de contrôle dans l'UTF-8. Par exemple, 00 représente le caractère NULL, et 0A représente le saut de ligne (LF).
Caractères Non-ASCII : UTF-8 est conçu pour être rétrocompatible avec ASCII. Les caractères ASCII (de 00 à 7F) sont représentés par un seul octet en UTF-8, identique à leur représentation ASCII. Les caractères au-delà de la plage ASCII utilisent des séquences de 2 à 4 octets. Par exemple, le caractère 'é' (é accent aigu) est représenté par C3 A9 en UTF-8.
Caractères Surrogates : Dans le système de codage UTF-16, certains caractères sont représentés par des paires de surrogates. En UTF-8, ces caractères sont représentés par des séquences de 3 ou 4 octets. Par exemple, les caractères emoji sont souvent représentés par des séquences de 4 octets en UTF-8.
Caractères Illégaux : Certaines séquences d'octets ne sont pas autorisées en UTF-8, car elles ne correspondent à aucun caractère valide ou sont utilisées pour coder des caractères d'une manière non conforme à la norme UTF-8. Lorsqu'un logiciel rencontre de telles séquences, il peut les remplacer par le caractère de substitution EF BF BD.

Voici un code qui lit et détecte la présence de la séquence de substitution: EF BF BD
Function BinaryToHex(binary)
   ' // Dim i, hexa
    hexa = ""
    For i = 1 To LenB(binary)
        hexa = hexa & Right("0" & Hex(AscB(MidB(binary, i, 1))), 2)
    Next
    BinaryToHex = hexa
End Function

Function ContainsEFBFBD(filePath)
    Dim stream, binaryData, hexData
    Set stream = CreateObject("ADODB.Stream")
    stream.Type = 1 ' Binary
    stream.Open
    stream.LoadFromFile(filePath)
    binaryData = stream.Read
    stream.Close
    hexData = BinaryToHex(binaryData)
    If InStr(hexData, "EFBFBD") > 0 Then
        ContainsEFBFBD = True
    Else
        ContainsEFBFBD = False
    End If
End Function

' Exemple d'utilisation
'Dim filePath
'filePath = "chemin_du_fichier"
'If ContainsEFBFBD(filePath) Then
'   WScript.Echo "Le fichier contient la séquence EFBFBD."
'Else
'   WScript.Echo "La séquence EFBFBD n'est pas présente dans le fichier."
'End If

Da

					    Function CountEFBFBD(filePath)
    Dim stream, binaryData
    Set stream = CreateObject("ADODB.Stream")
    stream.Type = 1 ' Binary
    stream.Open
    stream.LoadFromFile(filePath)
    binaryData = stream.Read
    stream.Close

    ' Compter les occurrences de la séquence EFBFBD
    Dim i, count
    count = 0
    For i = 1 To LenB(binaryData) - 2
        If AscB(MidB(binaryData, i, 1)) = &HEF And _
           AscB(MidB(binaryData, i + 1, 1)) = &HBF And _
           AscB(MidB(binaryData, i + 2, 1)) = &HBD Then
            count = count + 1
        End If
    Next

    CountEFBFBD = count
End Function

' Exemple d'utilisation
Dim filePath
filePath = "chemin_du_fichier"
Dim occurrences
occurrences = CountEFBFBD(filePath)
WScript.Echo "Nombre d'occurrences de la séquence EFBFBD : " & occurrences

L'objet ADODB.Stream ne fournit pas directement une option pour ignorer la BOM (Byte Order Mark) lors de la lecture de fichiers. Toutefois, vous pouvez contourner ce problème en lisant d'abord les premiers octets du fichier pour vérifier la présence de la BOM, puis en continuant la lecture du reste du fichier si nécessaire. Voici un exemple général de la façon dont vous pourriez procéder :
Ouvrir le fichier en mode binaire : Commencez par ouvrir le fichier en mode binaire pour lire les premiers octets.
Lire les premiers octets : Lisez les premiers octets du fichier pour déterminer s'ils correspondent à la BOM UTF-8 (EF BB BF).
Repositionner le pointeur de flux : Si la BOM est présente, positionnez le pointeur de flux juste après la BOM. Si la BOM n'est pas présente, repositionnez le pointeur au début du fichier.
Lire le reste du fichier : Changez le mode en texte (avec l'encodage UTF-8 si nécessaire) et lisez le reste du fichier.
Voici un exemple de code en VBScript illustrant cette approche :

Dim objStream
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = 1 ' Binary
objStream.Open
objStream.LoadFromFile("chemin_du_fichier")

' Lire les premiers 3 octets
Dim bom
bom = objStream.Read(3)

' Vérifier la BOM pour UTF-8 (EF BB BF)
If bom <> ChrB(&HEF) & ChrB(&HBB) & ChrB(&HBF) Then
    ' Pas de BOM, remettre le pointeur au début
    objStream.Position = 0
End If

' Changer le type en texte et définir l'encodage
objStream.Type = 2 ' Text
objStream.CharSet = "utf-8"
Dim text
text = objStream.ReadText

' Traiter le texte...
' ...
objStream.Close

Bug d'encodage : des octets UTF-8 vu en Windows-1252 ou ISO-8859-1

Au lieu d'un caractère attendu, une séquence de caractères latins est affichée, commençant généralement par à ou Â. Par exemple, au lieu de "è", ces caractères apparaissent : "è".

Explication : les caractères encodés en UTF-8 ont leurs octets individuels interprétés en ISO-8859-1 ou Windows-1252. Par exemple, sur une page web est codée en caractères UTF-8, si le serveur ou le navigateur déclare, par erreur, que le jeu de caractères est ISO-8859-1, le navigateur affichera alors chacun des octets UTF-8 de la page web comme des caractères latins-1.
Un caractère tel que è (e-Grave, U+00E8) se compose de deux octets en UTF-8 : 0xC3 et 0xA8. Si chacun de ces octets est traité comme un point de code ISO-8859-1 ou Windows-1252, les caractères affichés seront à et ¨.