OVH Cloud OVH Cloud

Détecter UTF8

14 réponses
Avatar
Gloops
Bonjour tout le monde,

J'ai bien un jeu de fonctions pour convertir UTF8 en ANSI et
inversement, mais maintenant la question serait plutôt de savoir SI le
contenu d'une chaîne de caractères est en UTF8, pour savoir si il doit
être converti (si on fait la conversion à tort on perd les caractères
accentués).

Je ne me fais pas trop d'illusions, mais peut-être que quelqu'un sait
faire ...

J'ai fait un récapitulatif d'une boîte mail d'Eudora, ça se passe bien
sauf sur ce point. Comme la boîte contient des messages en UTF8 (envoyés
depuis un site webmail) et des messages en ISO8859, il s'agit de faire
le tri. J'ai bien regardé au début du message, dans le code HTML, et je
n'y ai pas trouvé ce que je cherchais. Pas à la fin, quand même ?

Si ça se trouve il y a un manque au niveau du stockage, comme Eudora
assurera bientôt le support UTF8 ça résoudra la question, mais si jamais
quelqu'un a une idée géniale ça serait dommage de s'en priver.


A tout hasard je remets le code de la conversion, puisque je trouve
beaucoup plus facilement les messages des gens qui demandent comment on
fait, que la réponse. De ce fait j'ai oublié qui me l'a donné, désolé.

Conversion UTF-8 / ANSI
' =======================================
Option Explicit

Private Declare Function MultiByteToWideChar Lib "Kernel32" _
(ByVal CodePage As Long, ByVal dwFlags As Long, _
ByVal lpMultiByteStr As Long, ByVal cchMultiByte As Long, _
ByVal lpWideCharStr As Long, ByVal cchWideChar As Long) As Long

Private Declare Function WideCharToMultiByte Lib "Kernel32" _
(ByVal CodePage As Long, ByVal dwFlags As Long, _
ByVal lpWideCharStr As Long, ByVal cchWideChar As Long, _
ByVal lpMultiByteStr As Long, ByVal cchMultiByte As Long, _
ByVal lpDefaultChar As Long, ByVal lpUsedDefaultChar As Long) _
As Long

Private Const CP_ACP = 0
Private Const CP_UTF8 = 65001
' =======================================
Public Function UTF8_Encode(ByVal Text As String) As String

Dim sBuffer As String
Dim lLength As Long

lLength = WideCharToMultiByte(CP_UTF8, 0, StrPtr(Text), -1, 0, 0, 0, 0)
sBuffer = Space$(lLength)
lLength = WideCharToMultiByte(CP_UTF8, 0, _
StrPtr(Text), -1, StrPtr(sBuffer), Len(sBuffer), 0, 0)
sBuffer = StrConv(sBuffer, vbUnicode)
UTF8_Encode = Left$(sBuffer, lLength - 1)

End Function
' =======================================
Public Function UTF8_Decode(ByVal Text As String) As String

Dim lLength As Long
Dim sBuffer As String

Text = StrConv(Text, vbFromUnicode)
lLength = MultiByteToWideChar(CP_UTF8, 0, StrPtr(Text), -1, 0, 0)
sBuffer = Space$(lLength)
lLength = MultiByteToWideChar(CP_UTF8, 0, _
StrPtr(Text), -1, StrPtr(sBuffer), Len(sBuffer))
UTF8_Decode = Left$(sBuffer, lLength - 1)

End Function

10 réponses

1 2
Avatar
Fred
dans : news:43a99ac8$0$18308$
Gloops disait :
Bonjour tout le monde,



Bonjour,


J'ai bien un jeu de fonctions pour convertir UTF8 en ANSI et
inversement, mais maintenant la question serait plutôt de savoir SI le
contenu d'une chaîne de caractères est en UTF8, pour savoir si il doit
être converti (si on fait la conversion à tort on perd les caractères
accentués).



Pour commencer, s'il s'agit de messages, il devrait y avoir un encodage
de spécifié.
Dans le cas contraire on ne peut que jouer aux devinettes.
Quelques éléments qui peuvent t'aider :
1) il peut y avoir une séquence d'octets appelées BOM au début (mais je
n'y crois pas trop)
Si le flux commence par EF BB BF, c'est de l'UTF-8
2) un flux UTF-8 ne contient *jamais* C0, C1, ainsi que les valeurs de
F5 à FF
3) les séquences d'octets supérieurs à 7F répondent aux règles suivantes
:
- le nombre de bits de poids fort à 1 du premier octet donne le
nombre d'octets de la séquence
ainsi, une séquence de 2 octets commence avec un octet 110xxxxx
une séquence de 3 octets avec 1110xxxx
4 octets 11110xxx (c'est le maximum)
- tous les octets suivants de la séquence ressemblent à 10xxxxxx

Plus de détails ici : http://www.ietf.org/rfc/rfc3629.txt

Bonne programmation ;-)


--
Fred
http://www.cerbermail.com/?3kA6ftaCvT
Avatar
Gloops
Ah, ben voilà au moins des infos.

Merci.
Avatar
Fred
Dans : news:43aacc90$0$18324$
Gloops écrit :
Ah, ben voilà au moins des infos.

Merci.



De rien,
Tu peux te faire un petit algorithme très rapide et amusant sur le
principe des automates d'états finis.
En une passe (ou moins) tu peux déterminer de façon certaine si ce n'est
pas de l'UTF-8.
Si tu ne connais pas je repasserai plus tard pour détailler.
À moins que tu aies déjà ton idée pour programmer cela !

--
Fred
http://www.cerbermail.com/?3kA6ftaCvT
Avatar
Gloops
Ah, intéressant.
Si je vois certaines successions de deux caractères je sais que c'est de
l'UTF-8, pour être sûr que ce n'est pas le cas ... pour le moment je
suis dans le flou.

Il faudrait que je m'accorde une heure là-dessus, déjà.

Le principe des automates d'état fini ... hum, je demanderai à mon pote
Google ce que c'est.
___________________________________
Fred a écrit, le 22/12/2005 17:06 :
De rien,
Tu peux te faire un petit algorithme très rapide et amusant sur le
principe des automates d'états finis.
En une passe (ou moins) tu peux déterminer de façon certaine si ce n'est
pas de l'UTF-8.
Si tu ne connais pas je repasserai plus tard pour détailler.
À moins que tu aies déjà ton idée pour programmer cela !



Avatar
Fred
Dans : news:43aaece3$0$20151$,
Gloops disait :

Si je vois certaines successions de deux caractères je sais que c'est
de l'UTF-8,



C'est le contraire, tu peux conclure que ce n'est pas de l'UTF-8 dans
certains cas, mais tu ne peux jamais conclure que cela en est ;-)
Je t'accorde que la probabilité d'arriver au bout de tes octets en ayant
validé toutes les règles précédentes avec autre chose que de l'UTF-8 est
proche de zéro.

Sauf avec de l'ASCII (du vrai, sur 7 bits), tu arriveras à la conclusion
qu'il s'agit d'un encodage UTF-8. Mais c'est normal. L'UTF-8 a été pensé
pour être compatible avec l'ASCII (tous les octets inférieurs à 7F
représentent le caractère correspondant dans le jeu ASCII). Donc, si
tous les octets sont inférieurs à 7F, c'est ASCII *et* UTF-8. De quoi y
perdre son Latin (9).

--
Fred
http://www.cerbermail.com/?3kA6ftaCvT
Avatar
Jean-Marc
"Gloops" a écrit dans le message de
news:43aaece3$0$20151$
Ah, intéressant.
Si je vois certaines successions de deux caractères je sais que c'est


de
l'UTF-8, pour être sûr que ce n'est pas le cas ... pour le moment je
suis dans le flou.

Il faudrait que je m'accorde une heure là-dessus, déjà.

Le principe des automates d'état fini ... hum, je demanderai à mon


pote
Google ce que c'est.



Hello,


Les automates à états finis sont un moyen classique et très élégant
pour résoudre un grand nombre de problèmes, notamment pour écrire des
parsers ou des validateurs de toutes sortes. On peut faire plein
d'autres choses mais ce n'est pas le sujet ici. Comment ça marche?

Les automates sont basé sur 2 concepts: les états et les transitions.
Un automate admet un état initial et un ou des états finaux, plus des
états intermédiaires. Une transition est simplement une condition
permettant de passer d'un état à un autre.

Construisons un automate dont le travail est de déterminer si une chaine
de caractères est un nombre ou pas.

Modélisons le problème:
- on peut commencer par un chiffre, le signe moins ou un point
- si on commence par un signe moins, le prochain caractère doit être un
point ou un chiffre
- si on commence par un point, le caractère suivant doit être un chiffre
- si on commence par un chiffre, le caractère suivant doit être un
chiffre ou un point
- après un point, il faut au moins un chiffre, et plus jamais de points
- apres un chiffre, on peut trouver un autre chiffre ou un point, pour
autant que ce soit le premier point rencontré.

Dessinons maintenant l'automate correspondant:


chiffre
+-----------> 1
|
signe (-) | point (.)
+------------> 2 -----------------------+
| | +--+
| point (.) point (.) ! chiffre ! | chiffre
| -----------> +----------------------> 3 ---------> 4----+
chiffre | |
0 -----------> 1 <-+ ! PAS chiffre
| /| | chiffre 5
| / +---+
| /
| / PAS chiffre
+--> 5 <--/

Les états sont représentés par des numéros: 0, 1, 2, 3, 4, 5
Les transitions sont les flêches qui partent des états. La condition de
transition est indiquée au dessus de la flêche.

Sur ce graphe, l'état initial est l'état 0 (zéro).

Les états terminaux sont les états 1, 4. L'état 5 est particulier,
c'est un état qui n'a pas de transition sortante. Il est terminal de
fait, mais invalide.

On lit donc la chaine caractère par caractère, et selon l'état dans
lequel on se trouve, on regarde les transitions possibles. Si on trouve
une transition possible, on passe dans l'état correspondant.

Quand il n'y a plus de caractères, il suffit de regarder dans quel état
de l'automate on se trouve. Si on n'est dans un état final et valide (1
ou 4 dans cet exemple), alors la réponse pour le problème est "VRAI",
sinon la réponse est "FAUX".

Maintenant, le plus beau: une fois que la modélisation est faite, le
codage est trivial et est même carrément mécanique; on peut même écrire
des générateurs de code qui en partant d'une description d'un automate
génère le code correspondant, en n'importe quel langage.

Je le prouve avec l'automate correspondant à cet exemple:

Function estUnNombre(s As String) As Boolean
Dim etat As Integer
Dim car As String
Dim l As Long
Dim i As Long

l = Len(s) ' longueur de la chaine d'entrée
If l > 0 Then ' si pas vide
etat = 0 ' on se met dans l'etat initial

For i = 1 To l ' puis on avance caractere par caractere
car = Mid$(s, i, 1)
Select Case etat ' et on suit l'automate
Case 0
If EstUnChiffre(car) Then
etat = 1
ElseIf EstSigneMoins(car) Then
etat = 2
ElseIf EstPoint(car) Then
etat = 3
Else
etat = 5 ' fini
End If
Case 1
If EstUnChiffre(car) Then
etat = 1
ElseIf EstPoint(car) Then
etat = 3
Else
etat = 5 ' fini
End If
Case 2
If EstUnChiffre(car) Then
etat = 1
ElseIf EstPoint(car) Then
etat = 3
End If
Case 3
If EstUnChiffre(car) Then
etat = 4
End If
Case 4
If EstUnChiffre(car) Then
etat = 4
Else
etat = 5 ' fini
End If
Case 5
' etat invalide, pas de transitions
' on peut quitter ici si on veut
End Select
Next i
End If

If etat = 1 Or etat = 4 Then
estUnNombre = True
Else
estUnNombre = False
End If
End Function


Private Function EstUnChiffre(car As String) As Boolean
If car >= "0" And car <= "9" Then
EstUnChiffre = True
End If
End Function

Private Function EstSigneMoins(car As String) As Boolean
If car = "-" Then
EstSigneMoins = True
End If
End Function

Private Function EstPoint(car As String) As Boolean
If car = "." Then
EstPoint = True
End If
End Function

Pour généraliser à n'importe quel automate, il suffit d'écrire les
fonctions de transition, qui sont en général très simples.


Espérant que ça aide, bonne programmation :-)

--
Jean-marc
Tester mon serveur (VB6) => http://myjmnhome.dyndns.org
"There are only 10 kind of people
those who understand binary and those who don't."
mailto: remove '_no_spam_' ;
Avatar
Gloops
Salut,

Bon, il y a du nouveau.
J'ai eu un problème avec la réception d'un message qui me mettait le
bazar à l'ouverture de la messagerie, ça m'a donné l'occasion de
m'intéresser de plus près à la norme MIME.

Aussi j'ai regardé le contenu de ma boîte d'entrée à l'aide d'un éditeur
de texte, là j'ai vu que la plupart des messages ont un ou des champs
Content-type. Logiquement, on peut s'attendre à ce que ceux qui n'en ont
pas soient tous du même type, ou alors ça va être dur pour mes cheveux ...

Peut-être y a-t-il une faiblesse de l'objet d'accès à la boîte, si cette
propriété n'est pas accessible individuellement avec. Je verrai cela
dans le newsgroup Eudora, des fois que j'aie mal regardé, ce serait quan
même plus simple. Toujours est-il qu'il y a une propriété RawMessage qui
retourne tout le texte reçu au titre du message, champs inclus. Ce n'est
pas la solution la plus élégante mais en faisant une recherche là-dedans
avec InStr on devrait s'en sortir. Si c'est ça qu'il faut faire, ça
promet quand même d'être du sport pour les multipart ...

Merci pour les réponses.
Avatar
Gloops
Fred a écrit, le 22/12/2005 21:41 :

C'est le contraire, tu peux conclure que ce n'est pas de l'UTF-8 dans
certains cas, mais tu ne peux jamais conclure que cela en est ;-)



Même si tu vois
"cheminots en grève" ?

Je t'accorde que la probabilité d'arriver au bout de tes octets en ayant
validé toutes les règles précédentes avec autre chose que de l'UTF-8 est
proche de zéro.



Peut-être bien.

Sauf avec de l'ASCII (du vrai, sur 7 bits), tu arriveras à la conclusion
qu'il s'agit d'un encodage UTF-8. Mais c'est normal. L'UTF-8 a été pensé
pour être compatible avec l'ASCII (tous les octets inférieurs à 7F
représentent le caractère correspondant dans le jeu ASCII). Donc, si
tous les octets sont inférieurs à 7F, c'est ASCII *et* UTF-8. De quoi y
perdre son Latin (9).



Il y a des accents, en latin ? Ah oui, les accents toniques ...
Hum, c'est vrai que je ne fais pas souvent du VB en latin ...
Avatar
Gloops
Ah ben ça au moins c'est de la doc.
Je plonge là-dedans un de ces quatre, merci beaucoup.
Avatar
Gloops
Gloops a écrit, le 23/12/2005 00:04 :
ce serait quan
même plus simple.



Ah, quelquefois il y a des lettres qui restent dans les fils ...
1 2