Bonjour à toutes et à tous.
Lorsque j'importe un fichier .txt dans une TextBox, ce fichier peut être encodé soit en ANSI, soit en UTF8 (sans BOM).
L'affichage dans une TextBox est toujours ANSI.
Comment déterminer l'encodage du fichier .txt afin de savoir si je dois le convertir ou non ?
Merci d'avance pour vos réponses ! (ChatGPT n'y parvient pas)
Marc
Il y a quelques temps j'avais rencontré le même problème que toi et j'avais pondu un bout de code, qui ne vaut que ce qu'il vaut... mais qui fonctionnait avec les fichiers que j'utilisais.
Je t'ai construit un classeur-exemple avec les macros de l'époque, et ça a l'air de fonctionner avec tes trois fichiers qui sont bien détectés au format indiqué par leurs noms.
A toi de voir si tu peux en tirer quelque chose ou pas.
Hello,
pour détecter l'encodage d'un fichier texte sous windows on peut utiliser le module powershell EncodingAnalyzer (licence GPL) qui se trouve dans la galerie powershell.
Voici comment l'utiliser en VBA.
1 - Il faut d'abord importer le module sur sa machine (il se télécharge automatiquement si présent dans la galerie):
Pour tous les utilisateurs :
Ouvrir une invite de commande Powershell en étant administrateur et lancer :
Code:
Install-Module -Name EncodingAnalyzer
Que pour l'utiliseur courant :
Ouvrir une invite de commande Powershell et lancer :
Voici le code VBA pour utiliser la fonction Get-Encoding du module. Ce code utilise la fonction PS_GetOutput qui lance une commande powershell en utilisant la fonction de patricktoulon ShellAndwaitingEndProcess (lancer une commande et attendre qu'elle soit finie). La fonction PS_GetOutput renvoie le résultat de la commande (elle utilise le presse-papier pour récupérer ce résultat)
VB:
Sub DetectFileEncoding()
'Dim bm As New cBenchmark
Dim mesFichiers, Fichiers, Resultat As String, Lignes, Ligne
'bm.TrackByName "Init"
mesFichiers = Array("d:\temp\T1 UTF8.txt", "d:\temp\T2 UTF8-BOM.txt", "d:\temp\T3 ANSI.txt")
For Each Fichier In mesFichiers
Resultat = PS_GetOutput("Get-Encoding '" & Fichier & "' | ConvertTo-Csv -NoTypeInformation ")
' bm.TrackByName "PowerShell Execute"
Lignes = Split(Resultat, vbCrLf)
For Each Ligne In Lignes
Debug.Print Ligne
Next Ligne
' bm.TrackByName "Affiche Résultat"
Next Fichier
End Sub
Public Function PS_GetOutput(ByVal sPSCmd As String) As String
sPSCmd = "powershell -command " & sPSCmd & " | clip"
ShellAndwaitingEndProcess sPSCmd
With CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
.GetFromClipboard
PS_GetOutput = .GetText(1)
End With
End Function
Function ShellAndwaitingEndProcess(ByVal CheminComplet As String) As Long
Dim ProcessHandle As Long
Dim ProcessId As Long
ProcessId = Shell(CheminComplet, vbHide)
ProcessHandle = ExecuteExcel4Macro("CALL(""Kernel32"",""OpenProcess"",""JJJJ"",""" & 2031616 & """,""" & 0 & """,""" & ProcessId & """)")
ShellAndwaitingEndProcess = ExecuteExcel4Macro("CALL(""Kernel32"",""WaitForSingleObject"",""JJJJJ"",""" & ProcessHandle & """,""" & &HF0000 & """)")
End Function
Les lignes en commentaires dans DetectFileEncoding ont été utilisées pour calculer le temps d'exécution pour traiter 3 fichiers textes. Voici le résultat :
IDnr
Name
Count
Sum of tics
Percentage
Time sum
0
Init
1
78
0,00%
7800 ns
1
PowerShell Execute
3
22 655 101
99,85%
2,27 s
2
Affiche Résultat
3
45 397
0,15%
4,54 ms
TOTAL
7
22 700 576
100,00%
2,27 s
Total time recorded:
2,3 s
Et voici ce qui est retourné (en format csv) :
A noter que dans le PowerShell on peut lancer des commandes windows Exemple :
Il y a quelques temps j'avais rencontré le même problème que toi et j'avais pondu un bout de code, qui ne vaut que ce qu'il vaut... mais qui fonctionnait avec les fichiers que j'utilisais.
Je t'ai construit un classeur-exemple avec les macros de l'époque, et ça a l'air de fonctionner avec tes trois fichiers qui sont bien détectés au format indiqué par leurs noms.
A toi de voir si tu peux en tirer quelque chose ou pas.
Bonjour
j'ai retrouvé mes deux fonctions dans les version beta du créatorRibbonx
je viens de les retester et elles fonctionnent
VB:
Sub test1()
FileConvert_UTF8_To_Ansi "C:\Users\patricktoulon\Desktop\MacCustomUI.xml"
End Sub
Sub test2()
FileConvert_Ansi_To_UTF8 "C:\Users\patricktoulon\Desktop\MacCustomUI.xml"
End Sub
Function FileConvert_UTF8_To_Ansi(fich)
'patricktoulon creatorRibbonx V2.7
Dim lachaine As String, x, texte$: x = FreeFile
'test lecture binnaire
Open fich For Binary Access Read As #x: lachaine = String(LOF(x), " "): Get #x, , lachaine: Close #x
If lachaine Like "*Ã*" Then 'si la chaine contient des carateres bizarres
With CreateObject("ADODB.Stream"): .Charset = "utf-8": .Open: .LoadFromFile (fich): texte = .ReadText(): End With
Kill fich
x = FreeFile: Open fich For Output As #x: Print #x, texte: Close #x
Else: MsgBox "ce fichier n'est pas encodé en utf-8"
End If
End Function
Function FileConvert_Ansi_To_UTF8(fich)
'patricktoulon creatorRibbonx V2.7
Dim lachaine As String, x, texte$: x = FreeFile
'test lecture binnaire
Open fich For Binary Access Read As #x: lachaine = String(LOF(x), " "): Get #x, , lachaine: Close #x
If Not lachaine Like "*Ã*" Then 'si la chaine ne contient pas de carateres sbizarre
Kill fich
Dim oStream
Set oStream = CreateObject("ADODB.Stream")
oStream.Charset = "utf-8"
oStream.Open
oStream.WriteText lachaine
oStream.SaveToFile fich, 2
Else: MsgBox "ce fichier est déjà encodé en utf-8"
End If
End Function
edit:
je me souviens ca y est
je les avais abandonné car si le texte ne contient pas de caractères particulier le utf8 passe pour du ansi
c'est pour ça que j'ai opter pour les 3 premier caractères en lecture binaire
Bonjour
j'ai retrouvé mes deux fonctions dans les version beta du créatorRibbonx
je viens de les retester et elles fonctionnent
VB:
Sub test1()
FileConvert_UTF8_To_Ansi "C:\Users\patricktoulon\Desktop\MacCustomUI.xml"
End Sub
Sub test2()
FileConvert_Ansi_To_UTF8 "C:\Users\patricktoulon\Desktop\MacCustomUI.xml"
End Sub
Function FileConvert_UTF8_To_Ansi(fich)
'patricktoulon creatorRibbonx V2.7
Dim lachaine As String, x, texte$: x = FreeFile
'test lecture binnaire
Open fich For Binary Access Read As #x: lachaine = String(LOF(x), " "): Get #x, , lachaine: Close #x
If lachaine Like "*Ã*" Then 'si la chaine contient des carateres bizarres
With CreateObject("ADODB.Stream"): .Charset = "utf-8": .Open: .LoadFromFile (fich): texte = .ReadText(): End With
Kill fich
x = FreeFile: Open fich For Output As #x: Print #x, texte: Close #x
Else: MsgBox "ce fichier n'est pas encodé en utf-8"
End If
End Function
Function FileConvert_Ansi_To_UTF8(fich)
'patricktoulon creatorRibbonx V2.7
Dim lachaine As String, x, texte$: x = FreeFile
'test lecture binnaire
Open fich For Binary Access Read As #x: lachaine = String(LOF(x), " "): Get #x, , lachaine: Close #x
If Not lachaine Like "*Ã*" Then 'si la chaine ne contient pas de carateres sbizarre
Kill fich
Dim oStream
Set oStream = CreateObject("ADODB.Stream")
oStream.Charset = "utf-8"
oStream.Open
oStream.WriteText lachaine
oStream.SaveToFile fich, 2
Else: MsgBox "ce fichier est déjà encodé en utf-8"
End If
End Function
edit:
je me souviens ca y est
je les avais abandonné car si le texte ne contient pas de caractères particulier le utf8 passe pour du ansi
c'est pour ça que j'ai opter pour les 3 premier caractères en lecture binaire
Merci beaucoup Patrick.
Mais entre-temps, TooFatBoy m'a apporté une solution qui marche parfaitement.
Quoi qu'il en soit, merci à toi d'avoir bien voulu te pencher sur ce cas et je garde sous la main ces codes que tu m'envoie "au cas où...".
Amicalement,
Marc
Attention, c'est loin d'être parfait. Comme je l'ai dit, ça ne vaut que ce que ça vaut...
Par exemple, si le fichier est encodé en UTF-8 mais qu'il ne comporte aucun caractères spéciaux (accentués ou autres), il sera considéré comme étant encodé en ANSI et donc certains caractères pourraient être mal décodés.
De plus, la macro essaye de détecter si c'est de l'UTF-8, elle considère que c'est, soit de l'UTF-8 (avec possibilité de se tromper), soit (si ce n'est pas de l'UTF-8) de l'ANSI. Elle ne "gère" aucun autre encodage.
Elle ne regarde pas s'il y a le BOM, ce qui permettrait d'être sûr que le fichier est encodé en UTF-8.
Ceci dit, ce n'est pas très grave car d'après ce que j'ai compris le BOM n'est plus vraiment utilisé de nos jours.
Il faut donc que tu aies bien en tête que la macro peut se tromper, même si à mon avis les chances sont quasiment nulles, mais ça peut arriver.
@TooFatBoy
c'est exactement ce que j'ai dis juste avant
c'est pour ça que j'ai abandonné cette methode de teste avec le caractère special
et opté pour les trois bytes
Attention, c'est loin d'être parfait. Comme je l'ai dit, ça ne vaut que ce que ça vaut...
Par exemple, si le fichier est encodé en UTF-8 mais qu'il ne comporte aucun caractères spéciaux (accentués ou autres), il sera considéré comme étant encodé en ANSI et donc certains caractères pourraient être mal décodés.
De plus, la macro essaye de détecter si c'est de l'UTF-8, elle considère que c'est, soit de l'UTF-8 (avec possibilité de se tromper), soit (si ce n'est pas de l'UTF-8) de l'ANSI. Elle ne "gère" aucun autre encodage.
Elle ne regarde pas s'il y a le BOM, ce qui permettrait d'être sûr que le fichier est encodé en UTF-8.
Ceci dit, ce n'est pas très grave car d'après ce que j'ai compris le BOM n'est plus vraiment utilisé de nos jours.
Il faut donc que tu aies bien en tête que la macro peut se tromper, même si à mon avis les chances sont quasiment nulles, mais ça peut arriver.
Bonjour TooFatBoy.
J'ai bien vu que le test ne se faisait finalement que sur un seul caractère "Ã" mais étant donné que mes textes font en général plus de 1000 caractères, il faudrait un hasard immense pour que ce caractère ne s'y retrouve pas.
D'autre part, s'il arrive que le texte ne s'affiche pas correctement, je pourrai toujours le convertir avec Notepad++. Ce serait une opération supplémentaire mais étant donné la rareté des cas, ce n'est pas bien grave.
Bonne journée.
Marc
J'ai bien vu que le test ne se faisait finalement que sur un seul caractère "Ã" mais étant donné que mes textes font en général plus de 1000 caractères, il faudrait un hasard immense pour que ce caractère ne s'y retrouve pas.