Détecter certains caractères spéciaux dans un titre

Bonjour à tous,

Voici mon problème : je dois checker des titres de documents pour être sûre qu'ils ne comprennent pas certains caractères spéciaux et colorer la cellule en rouge en cas de caractère spécial détecté. Jusqu'ici, je m'étais débrouillée comme ça :

'Checking if there is no special character except "-" in column F (Document Title)

Dim zx As Long, ax As Integer

ax = Sheets("VendorDocument").ListObjects("Table1").ListColumns("Document Title").Index

dl = Cells(Rows.Count, ax).End(xlUp).Row

For zx = 1 To dl

If Not ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Value Like "*[!A-Za-z0-9 -]*" Then

ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Interior.Color = xlNone

Else

ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Interior.Color = vbRed

End If

Next zx

Jusqu'à maintenant, seul le "-" était une exception, mais j'ai eu un retour et finalement, pas mal de caractères spéciaux sont finalement acceptés, et j'ai réussi à me procurer la liste des caractères spéciaux qui ne le sont pas : ~ " # % ' & * : ; , < > ? / \ { | }. (le . en fait partie, ainsi que le double espace)

Du coup, je dois modifier ma macro, mais j'avoue que je sèche sur sa reformulation, car je n'arrive pas à intégrer InStr à ma manière de formuler ma macro. Des idées ?

Merci d'avance et bonne journée !

Aelyth

Bonjour Aelyth,

Qu'est-ce qu'il vous faut et surtout qu'est-ce qu'il faut exclure ?

Voici un premier essai. Il faut ajouter la référence "Microsoft VBScript Regular Expressions 5.5" dans Outils/référence :

Function MATCH_CARS(chaine As String) As boolean

Dim ExpReg As REGEXP
Dim modele$

Set ExpReg = CreateObject("vbscript.regexp")
modele = "^(\w| ?|-?)+$" 'caractères alphanumériques ou underscore, espace simple et tiret

With ExpReg
    .Global = True
    .Pattern = modele
    If .test(chaine) Then
        MATCH_CARS = True
    End If
End With

End function

Pour l'instant, on accepte les les lettres, les chiffres, les _, les tirets et espaces simples. Mais ce sera à améliorer probablement...

A appeler comme ça dans votre code :

If Not MATCH_CARS(ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Value) Then

Même si j'aurais dit de colorier en rouge justement quand des caractères spéciaux sont trouvés...

Cdlt,

Bonjour Aelyth, bonjour 3GB

autre solution

If ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Value Like "*[~#%'&\*:;,<>\?/\\\{\|\}]*" Then

Bonjour à tous,

J'étais parti sur les expressions régulières comme 3GB, mais effectivement je pense que ce que propose Steelson est plus rapide et efficace.

@Steelson : Pourquoi indiquer plusieurs fois '\\\' ?

En reprenant ton code et en ajoutant le double espace :

If ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Value Like "*[~#%'&\*:;,<>\?/\\\{\|\}  ]*" Then

EDIT : Erratum, le double espace n'est pas pris en compte avec le code que j'ai fourni

Merci encore Steelson.

Le truc, c'est qu'il faut également empêcher les double espaces... D'où l'utilisation des expressions régulières (que j'ai d'ailleurs découvertes grâce à toi ).

A voir...

Salut Baboutz,

L'antislash sert à introduire les caractères "spéciaux" ("*", "?" par ex) ayant un rôle dans la recherche.

Et donc, ici, pour son introduction, l'antislash est doublé \\ puis est suivi de l'accolade ouvrante \{. On obtient donc le triple antislash mais les 2 premiers et le troisième ne sont pas liés...

Merci 3GB, si j'ai bien compris :

Si je résume :

  • \\ Introduit les caractères "spéciaux"
  • \{ Indique le caractère "spécial" : {

Pourquoi ne pas avoir introduit ? de cette manière alors : \? ?

De plus je viens faire le test

If valeur Like "*[~#%'&\*:;,<>\?/{|}]*" Then

Bloque bien ces caractères "spéciaux"...

Je crois que tu m'as compris mais je le précise car j'ai l'impression que tu as écrit trop vite :

\ instruit que le caractère suivant sera lu comme un caractère et non pas interprété pour sa fonction dans les recherches sur les chaines.

"\\" introduit le caractère "\"

"\{" introduit le caractère "{"

Si, si tu regardes bien, il y a bien \? pour tester le caractère "?"

En revanche, on trouve "*" en début et en fin de modèle pour signifier tout caractère quelconque, mais au sein du modèle, on le trouve bien ainsi : "\*".

Je ne sais pas exactement comment ça marche avec l'opérateur Like mais je crois qu'il faut au moins mettre l'antislash devant le #, le * et le ?, et probablement le !. Pour le reste, je ne suis pas sûr mais je pense que les expressions régulières permettent de mieux cadrer le modèle, et notamment ici le double espace...

Voici la liste des caractères aussi utilisés comme symboles spéciaux dans les expressions régulières et qu'il faut donc faire précéder par \ : (, ), [, ], ., *, ?, +, ^, |, $ , - et \

C'est pourquoi j'ai mis

  • \\ pour détrecter un \
  • \? pour détecter un point d'interrogation
  • etc.
  • \* pour détecter un astérisque, mais en début et en fin de string il sert bien comme symbole spécial désignant n'importe quel caractère

3GB a bien résumé la situation.

Pour le double espace, on peut mettre aussi like "*  *"

ce qui ferait

If ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Value Like "*[~#%'&\*:;,<>\?/\\\{\|\}]*" or ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Value Like "*  *" Then

car je ne pense pas que le double espace entre [ et ] soit pris comme tel mais plutôt comme une redondance d'un simple espace.

Merci à vous deux, j'ai bien compris maintenant ! J'avais mal compris la première au début, mais maintenant c'est clair. C'est assez logique!

Je vais marquer ça dans mon petit mémo VBA

car je ne pense pas que le double espace entre [ et ] soit pris comme tel mais plutôt comme une redondance d'un simple espace.

Oui en effet, c'est ce que j'ai remarqué après !

Voici la fonction que j'avais faite pour tester

Function ok(cel As Range) As Boolean
If cel.Value Like "*[~#%'&\*:;,<>\?/\\\{\|\}]*" Or cel.Value Like "*  *" Then ok = False Else ok = True
End Function

on est trop peu à s'intéresser aux expressions régulières qui sont d'une puissance considérable (et universelles quelque soit le langage)

En effet, compte tenu du besoin, rajouter or ... Like "* *" est probablement ce qu'il y a de mieux...

Pour le reste, je vais faire des petits essais car je ne sais pas si les "expressions régulières" de VBA se comportent exactement comme l'objet ExpReg.

Et d'ailleurs, après quelques recherches, il semble que l'antislash ne concerne que l'objet ExpReg et pas les expressions régulières de VBA. Le simple fait de mettre entre crochet les caractères "*", "?", "[" et "#" suffirait. Le crochet fermant "]" (et le point d'exclamation j'imagine) est à gérer individuellement... Les autres caractères "spéciaux" (y compris le "\") auraient la seule valeur de caractère de chaine et non de modèle.

A voir...

Mais en effet, c'est vraiment passionnant !

ok, fais nous un topo là-dessus ... généralement je les utilise comme toi au travers de CreateObject("vbscript.regexp") et plus rarement avec like

J'ai découvert ça cette semaine justement et en effet, c'est hyper puissant et sous-exploité !

@Steelson : Es-tu sur que VBA interprète ça comme des expressions régulières avec l'opérateur Like ? Car après un test,

If ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Value Like "*[~#%'&\*:;,<>\?/\\\{\|\}]*" Then

Me donne le même résultat que

If ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Value Like "*[~#%'&*:;,<>?/\{|}]*" Then

Sans les \ pour introduire le caractère spécial !

Ah, ben tant mieux au final ! Comme je le disais je suis plus habitué à vbscript.regexp ... mais ce serait troublant d'avoir 2 syntaxes différentes alors !

edit : tu as raison sauf pour \ qu'il faut doubler ...

edit2 : non, même pas !

Bonjour Aelyth, bonjour 3GB

autre solution

If ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Value Like "*[~#%'&\*:;,<>\?/\\\{\|\}]*" Then

Bonjour ! Super, merci, ça marche nickel pour moi ! Merci aux autres qui ont proposé une solution aussi ! :)

Baboutz : En effet, il n'y aurait pas besoin avec les "expressions régulières" (enfin les pattern) de VBA de recourir à l'antislash (contrairement aux expressions régulières).

Seuls les caractères *, ?, #, [, ], et ! (sauf omission de ma part) ont un rôle particulier et sont donc spéciaux ou des métacaractères. Les autres sont des caractères spéciaux normaux. Et pour traiter ces "métacaractères" (excusez ma terminologie ) comme du texte, il faut les placer entre crochets.

https://docs.microsoft.com/fr-fr/office/vba/language/reference/user-interface-help/like-operator

Steelson : Oui, l'opérateur Like sert à faire des comparaisons de chaines assez simples, où il y a seulement besoin de tester le minimum mais n'est pas aussi performant et complet que l'objet accessible grâce à CreateObject("vbscript.regexp") ou à l'ajout de la référence "Microsoft VBScript Regular Expressions 5.5" (permettant d'avoir accès aux propriétés et méthodes).

Et là, en effet, il y a bien plus de "métacaractères", tous ceux que tu as cités, qui sont à introduire, le cas échéant, en les précédant d'un \ lorsqu'on les teste comme caractères.

Je sais pas si je suis super clair et il faut pas hésiter à me corriger ou me faire connaitre les mots précis.

Bonjour Aelyth, bonjour 3GB

autre solution

If ActiveSheet.ListObjects("Table1").DataBodyRange(zx, ax).Value Like "*[~#%'&\*:;,<>\?/\\\{\|\}]*" Then

Bonjour ! Super, merci, ça marche nickel pour moi ! Merci aux autres qui ont proposé une solution aussi ! :)

ajoute le test sur le double espace que j'ai mis plus haut

Merci 3GB, c'est très clair pour moi !

Je viens faire un petit retour après tests :

En effet, pour les patterns VBA, nul besoin du \. Il suffit de placer *, ?, [, #, ! au sein du groupe de caractères entre crochets (il ne faut juste pas mettre ! en premier, qui fait office de négation dans ce cas du groupe entre crochets).
Le "]" est à traiter indépendamment, avec un autre Like "*]*".

En ce qui concerne mon expression régulière, j'étais relativement loin du compte notamment parce que j'ai mis un | (ou) au mauvais endroit et parce que \w correspond aux caractères alphanumériques NON ACCENTUES ! Il faut prévoir le rajout des accents, ce qui donnerait un modèle comme ça :

modele = "^(\wà?â?À?ç?Ç?é?è?ê?ë?É?È?Ê?î?ï?ô?ù?ü? ?-?)+$"

Ensuite, on peut se faire plaisir et rajouter ce qu'on veut ...

De cette manière, les chaines vides renvoient faux, tous les caractères spéciaux et de ponctuation renvoient faux, toutes les chaines avec un double espace, un double tiret ou une double lettre accentuée renvoient faux. Avec les lettres classiques, j'ai été relativement souple pour l'instant... En l'état, on peut commencer et finir par un espace ou un tiret mais il ne serait pas difficile de rajouter un petit niveau de validation pour les 1er et dernier caractères.

Rechercher des sujets similaires à "detecter certains caracteres speciaux titre"