Recherche de mot entier
Comment trouver un mot entier dans une requête Access ? Par exemple, dans une phrase comme «
Bonjour, aujourd'hui, c'est le jour de Noël !
« , je souhaite vérifier si la phrase contient le mot «jour
« .Un critère comme
[Le champ] LIKE '*jour*'
semble une bonne idée, mais le critère m’extrait les motsBonjour
,Aujourd'hui
etJour
. Alors que je ne souhaite extraire que le motJour
. Une phrase comme «Bonjour, c'est Noël
» serait considérée comme valide, et je n’en veux pas. Comment faire ?
Le problème des délimiteurs
Avec un peu d’astuce, on peut imaginer des critères du style :
[Le champ] LIKE '* jour *'
avec des espaces autour du mot jour
. Dans ce cas, Bonjour
et Aujourd'hui
sont effectivement éliminés.
Mais comment faire s’il y a un point, une virgule ou un tiret avant/après le mot « jour » ? Du genre : « Ce jour-là...
« . Le nombre de variantes devient lourd à gérer, et on sent que ça va donner un critère SQL long comme un jour sans ordinateur. 🙂
Les expressions régulières à la rescousse
C’est ici qu’il faut se rabattre sur les expressions régulières, dont il a été question dans d’autres articles du blog. Consultez notamment l’article Valider la saisie d’une adresse e-mail pour voir comment inscrire la bibliothèque VBScript Regular Expressions dans votre projet VBA.
La fonction VBA
Une fois la bibliothèque activée, recopiez cette fonction dans un module standard de votre base de données :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Function RechercheMot( _ ByVal strChaine As String, _ ByVal strMot As String) As Boolean ' On crée une expression rationnelle Dim re As VBScript_RegExp_55.RegExp Set re = New RegExp ' On définit le critère à respecter pour un mot entier re.Pattern = "b" & strMot & "b" re.IgnoreCase = True ' La fonction Test renvoie True si la chaîne ' respecte le critère RechercheMot = re.Test(strChaine) Set re = Nothing End Function |
Quelques explications :
- Si votre mot est
jour
, on va effectuer une recherche par l’expression régulièrebjourb
. - Le
b
détecte les limites (boundaries en anglais) d’un mot. Une limite pouvant être un espace, une tabulation, un tiret, un début de chaîne, une fin de chaîne. - En résumé, on cherche le mot jour compris entre des limites quelconques, mais pas collé à une autre portion de texte !
Tester la fonction
Pour tester la fonction rapidement :
- Faites apparaître la fenêtre Exécution (
CTRL
+G
). - Tapez-y des choses comme ça, en validant chaque ligne par
[Entrée]
:
La fonction renvoie Vrai
quand la phrase inspectée contient le mot entier, et Faux
sinon.
Vous remarquerez que les majuscules/minuscules ne sont pas importantes dans la recherche. Si vous souhaitez faire la distinction, remplacez re.IgnoreCase = True
par re.IgnoreCase = False
dans le listing plus haut.
Mettre la fonction en application
Tout ça devient plus intéressant dans une requête : je reprends ma base de films, et je voudrais trouver tous les films dont le résumé contient le mot « Elu
« . Première approche :
On obtient :
Le problème des 2 premiers films est que leur résumé contient le mot « celui
« , qui répond au critère. Aménageons la requête en ajoutant un champ calculé qui fait appel à la fonction VBA du dessus :
Cette fois, ça marche : seul Matrix sort dans les résultats. On a trouvé l’Elu !
Cinesra > Est-ce que tu peux poster ici un exemple de chaque requête (pour voir s’il y a quelque chose de particulier) ?
Les 2 mots sont-ils placés de la même manière dans le champ ?
Bonjour Hervé,
J’ai réussi à régler tous mes problèmes mis à part un tout petit détail:
Sais-tu pourquoi quand je recherche le mot « impureté » par exemple, la recherche fonctionne mais quand je recherche « émeraude », la recherche ne trouve rien (alors que l’enregistrement contenant le mot « émeraude » existe bel-et-bien?
Merci beaucoup d’avance
Bonjour Hervé,
J’ai trouvé la solution d’une de mes 2 questions (la seconde, celle d’hier) il suffit d’écrire:
Me.RecordSource = « SELECT * FROM MaTable WHERE (RechercheMot(Nz([MonChamp], »), ‘MotAChercher’) = True); »
Bonjour Cinesra, tout cela est excellent. Toutefois après essai avec Access 2010 la formulation : Me.RecordSource = “SELECT * FROM MaTable WHERE (RechercheMot(Nz([MonChamp],”), ‘MotAChercher’) = True);” entraine une erreur de syntaxe ; je ne suis pas encore assez expert en guillemets et virgules alors la « bonne » syntaxe serait bienvenue ! Si je n’en demande pas trop.
Avec mes remerciements anticipés.
gki
Bonjour, J’ai trouvé une syntaxe correcte avec une variable de travail :
Dim copiecritère As String
copiecritère = Forms![recherche sur descriptif seul].Critère
Me.RecordSource = « SELECT * FROM [inventaire1] WHERE (RechercheMot(Descriptif, ‘ » & copiecritère & « ‘) = True); »
Merci d’annuler ma demande précédente et merci pour toutes ces suggestions.
Salutations
gki
Super. Content que ça marche. 🙂
Rebonjour Hervé,
Encore une petite question concernant ton code (j’attends cependant toujours ta réponse pour pouvoir rechercher dans tous les champs d’une table à la fois).
Je viens de remarquer un détail plutôt gênant concernant ta fonction RechercheMot: lorsque qu’on recherche un mot dans le champ d’une table et que ce champ est vide pour certain enregistrements, la fonction RechercheMot retourne une erreur!! Évidemment une solution serait de mettre une valeur par défaut dans les champs à rechercher mais je trouve que ça fait un peu « mauvaise programmation », que c’est un peu lourd (d’autant que mettre des valeurs par défaut à la place d’un vide risque de faire gonfler le poids de ma base de données, non?).
Merci beaucoup d’avance pour une solution!!
Cinesra > On doit pouvoir faire de plusieurs manières. Par exemple, juxtaposer les
RechercheMot()
avec les mots-clefsEt
/Ou
:Sinon, on peut aussi retoucher le code même de la fonction pour qu’elle change l’expression régulière. En construisant une chaîne du style
bElub|bchevalb
le résultat vaudraTrue
si on trouveElu
oucheval
.Bonjour Hervé,
Comment modifier ton code pour permettre de chercher plusieurs mots à la fois, avec soit un « ET » entre chaque mot, soit un « OU »???
Merci d’avance