Expression régulière - Bizarrerie

cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 - 4 avril 2013 à 19:34
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 - 5 avril 2013 à 11:01
Salut ta tou(te)s

Dans la série "j'en découvre tous les jours", me voici confronté à une anomalie (à mon gout) :

Je bosse sur la vérification des Char qu'un champ XML peut accepter.
Les caractères acceptés sont, en hexa : 09, 0A, 0D, 20 à D7FF, E000 à FFFD et 10000 à 10FFFF.
J'ai donc construit un test basé sur une expression régulière dont voici le pattern :
Dim sPattern As String = "[^\x09\x0A\x0D\x20-\xD7FF\xE000-\xFFFD]"
Oui, il manque la dernière série 10000 à 10FFFF, mais j'ai voulu me simplifier la vie afin de pouvoir travailler ensuite avec des Char (65535 maxi).

Voilà le code que j'ai mis en place pour dire "si un caractère est interdit, on le remplace par un caractère de substitution" :
        Dim Anomalies As MatchCollection
        If String.IsNullOrEmpty(TheStringToCheck) Then Return TheStringToCheck
        Anomalies = Regex.Matches(TheStringToCheck, sPattern)
        If Anomalies.Count > 0 Then
            ' Prépare la liste des chars
            Dim aChars() As Char = TheStringToCheck.ToCharArray
            For Each Part As Match In Anomalies
                ' Remplace
                aChars(Part.Index) = cstBadXmlCharSubtitute  ' un #
            Next
            ' Reconstruit la chaine finale
            TheStringToCheck = New String(aChars)
        End If

Ce code semble fonctionner correctement, mais voilà, j'ai un caractère récalcitrant :
Je lui soumet une chaine comme celle-ci : "du texte ici – et du texte là"
Le symbole –, au lieu de la chaine, n'est pas un tiret classique. C'est un tiret que Word appelle "tiret demi-cadratin"; il est légèrement plus long qu'un tiret clavier.
Le code AscW(Part.Value) affiché lors de cette rencontre est 8211.

Or, 8211 (ou x2013) fait normalement partie des caractères autorisés, ceux dans le groupe x20 à xD7FF.
Alors pourquoi me l'a t-il détecté ?
Est-ce que la simplification des codes > 65535 expliqué au début aurait un rôle ?

NB : Je découvre RegEx depuis ce matin, et VB.Net depuis une semaine, et les "codes de caractères" sont nouveaux pour moi.

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

Le savoir est la seule matière qui s'accroit quand on le partage (Socrate)

12 réponses

NHenry Messages postés 15112 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 13 avril 2024 159
4 avril 2013 à 22:59
Bonjour,

AscW prend peut être pas le bon encodage, voir avec System.Text.Encoding.*.ToByteArray pour être sûr de l'encodage utilisé.

Sinon, tu peux aussi utiliser la classe System.Xml.* éventuellement en définissant UTF-8 comme encodage, comme ça cet espace de nom gèrera lui-même l'encodage des caractères qui pose pb.

Concernant les RegEx, j'ai "un peu" du mal avec.

Ou sinon, au pire, fais les contrôle avec AscW et en passant caractère par caractère, et en faisant ensuite une analyse avec un tableau de 2 colonne (min et max de chaque range).

v----Signature--------v----------------------------------------------
[list=ordered][*]Pour poser correctement une question et optimiser vos chances d'obtenir des réponses, pensez à lire le règlement CS, celui-ci pour bien poser votre question ou encore celui-ci pour les PFE et autres exercices.[*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : ).[*]En VB.NET pensez à activer Option Explicit et Option Strict (propriété du projet) et à retirer l'import automatique de l'espace de nom Microsoft.VisualBasic (onglet Références dans les propriétés du projet).[*]Si votre problème est résolu (et uniquement si c'est le cas), pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés/list
---
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
4 avril 2013 à 23:37
UTF8 : Normalement oui, le fichier que je lis sort justement d'une moulinette de conversion (de UTF-16).
Le caractère 8211 que je lis est bien présent dans le fichier source (lu avec un autre logiciel sérieux). Il ne semble pas y avoir de problème de ce côté là.

XML : C'est justement pour écrire sans générer d'erreur que je veux faire ce test des char interdits.

Le check char par char : Oui. Je pense que je vais en revenir à ma boucle de comparaison initiale.
C'est plutôt la recherche du problème qui est intéressante, faisant mes premiers pas avec RegEx.
Je l'ai étudié et testé toute la journée et j'aimerai bien savoir ce qui m'a échappé.

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

Le savoir est la seule matière qui s'accroit quand on le partage (Socrate)
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
4 avril 2013 à 23:39
Excuses, j'ai oublié de te saluer, Nico.
Merci
0
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
5 avril 2013 à 09:09
Bonjour à tous,
NHenry a vu juste, nous sommes bien en face d'un problème d'encodage.
Voici un petit exemple qui isole et met en avant le problème :
Dim reg As String = "\x2013" 'Recherche uniquement de tiret
Dim test As String = ChrW(8211) 'Devrait correspondre au fameux tiret

'Affiche pas le bon tiret mais peut importe, surement une limite de la console
Console.WriteLine(test) 

'Affiche bien "ASCW=2013"
Console.WriteLine("ASCW=" & AscW(test(0)).ToString("X2"))

'Affiche "UTF8=E280"
Dim utf8Table() As Byte = Encoding.UTF8.GetBytes(test(0))
Console.WriteLine("UTF8=" & utf8Table(0).ToString("X2") & utf8Table(1).ToString("X2"))

'Affiche 0 malheureusement
Dim Anomalies As MatchCollection= Regex.Matches(test, reg)
Console.WriteLine(Anomalies.Count)]


Il faut donc bien creuser du coté de l'encodage car on constate que AscW et ChrW n'utilisent pas l'UTF8.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
NHenry Messages postés 15112 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 13 avril 2024 159
5 avril 2013 à 09:22
Bonjour,

Je complète ma réponse.
Concernant UTF8 : http://sebsauvage.net/python/charsets_et_encoding.html
Normalement, Les classes XML traduisent les caractères interdits, donc évitent les erreurs

Ensuite, un petit rappel pour VB.NET :
En VB.NET pensez à activer Option Explicit et Option Strict (propriété du projet) et à retirer l'import automatique de l'espace de nom Microsoft.VisualBasic (onglet Références dans les propriétés du projet).

Il faut donc éviter ASCW et CHRW qui sont des fonctions héritées de VB6 et qui ne sont peut être plus adapté pour certains usages.

0
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
5 avril 2013 à 09:31
+1 pour désactiver "Microsoft.VisualBasic"

Cet assembly n'existe que par souci de compatibilité.

Mais bon, si jack viens juste de sauter le pas du VB6 au .NET. Autant commencer en douceur =D
0
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
5 avril 2013 à 09:40
Et voila les amis
Dim reg As String = "\u2013"
Dim test As String = Encoding.Unicode.GetString(New Byte() {&H13, &H20})

Dim Anomalies As MatchCollection = regex.Matches(test, reg)
Console.WriteLine(Anomalies.Count)


Remplacez \x par \u et le tour est joué
\u code unicode 16 bits
\U vode unicode 32 bits
0
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
5 avril 2013 à 10:15
Correction \U majuscule ne fonctionne pas.
Désolé. Je ne lisais pas la bonne documentation...
0
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
5 avril 2013 à 10:39
Et juste pour info, les RegEx permettent de faire de la substitution sans faire de boucle

Exemple
Dim TheStringToCheck As String = Encoding.Unicode.GetString(New Byte() {&H13, &H20})
Dim replaceReg As New Regex("\u2013")

TheStringToCheck = replaceReg.Replace(TheStringToCheck, cstBadXmlCharSubtitute)
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
5 avril 2013 à 10:53
Ah, voilà du grain à moudre; merci

Nicolas :
Dans le lien que tu as passé, j'aime bien la phrase "Chaque pays, culture, langue a développé son propre jeu de caractères. C'est un bordel pas possible.".
Ça me rassure, moi qui croyais ne pas comprendre grand chose, je suis un peu rassuré.

System.Xml corrige les caractères des attributs, pas des éléments simples (va savoir pourquoi).
Il va, par exemple, remplacer un espace dans le nom d'un attribut ou remplacer un & ou " dans une valeur d'attribut, mais rien pour les nom/valeur d'élément.

Référence à Microsoft.VisualBasic; je l'avais supprimée, riche des conseils souvent prodigués dans ce forum, mais c'est vrai qu'il est revenu --> Je ne savais pas qu'il y avait une option automatique de réapparition de la déclaration.
Je regarde ça.

Olivier :
Encore une syntaxe qui m'était inconnue.
En fait, il m'avait semblé avoir lu que Unicode de .Net était UTF-8 par défaut, raison pour laquelle je ne me suis pas focalisé dessus.

Merci pour ces pistes sérieuses.
Je mets en application et je reviens.
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
5 avril 2013 à 10:58
Merci Olivier pour l'astuce du Replace dans le RegEx; ça ira surement plus vite, but de ma recherche (je traite des fichiers de 90Mo).
Je vais tester ça aussi.
0
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
5 avril 2013 à 11:01
En fait, il m'avait semblé avoir lu que Unicode de .Net était UTF-8 par défaut, raison pour laquelle je ne me suis pas focalisé dessus.


UTF-32 => System.Text.Encoding.UTF32
UTF-16 => System.Text.Encoding.Unicode
UTF-8 => System.Text.Encoding.UTF8

En un p'tit lien pour le RegEx
0
Rejoignez-nous