FONCTION AVANCEES DE RECHERCHE ET D'EXTRACTION DE TEXTE.

cs_asimengo Messages postés 280 Date d'inscription jeudi 24 mars 2005 Statut Membre Dernière intervention 18 mars 2009 - 7 juil. 2006 à 12:52
cs_santiago69 Messages postés 91 Date d'inscription jeudi 18 novembre 2004 Statut Membre Dernière intervention 17 décembre 2008 - 15 août 2006 à 20:53
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/38474-fonction-avancees-de-recherche-et-d-extraction-de-texte

cs_santiago69 Messages postés 91 Date d'inscription jeudi 18 novembre 2004 Statut Membre Dernière intervention 17 décembre 2008
15 août 2006 à 20:53
Je t'envoi un message en prive pour eviter de surcharger les commentaires directement lies a cette source.
horneth Messages postés 6 Date d'inscription vendredi 9 juin 2006 Statut Membre Dernière intervention 22 juin 2010
15 août 2006 à 19:39
Bonjour, je suis totalement (mais alors totalement) débutant dans Visual Basic et j'essaye actuellement de faire un petit programme. En fait après avoir parcouru vos messages j'ai vu qu'il était question de rechercher une chaine de caracatere dans un fichier. Dans mon programme j'aurais besoin de rechercher un une chaine de caractere dans un fichier .txt, puis une fois la chaine trouvée, rechercher une autre chaine en partant de la première chaine et en revenant en arrière.

Je m'explique : Prenons la phrase "La fonction peut devenir quelque chose comme ceci" En clair je voudrait demander au programme qu'il trouve "comme ceci" dans cette phrase, puis une fois qu'il l'a trouvé, qu'il remonte en arrière jusqu'à trouver "La fonction", et ainsi qu'il puisse me renvoyer la phrase entière.

Voilà j'espère que c'est clair, je voudrais savoir si c'est possible et si cette fonction est capable de faire quelque chose semblable à ca.

Merci de votre aide.

Horneth
jean_marc_n2 Messages postés 170 Date d'inscription jeudi 11 décembre 2003 Statut Membre Dernière intervention 24 janvier 2009
27 juil. 2006 à 13:06
Oups il y a une coquille dans mon code. Il faut bien sur écrire: RevString3 = Space$(lg - 1)
jean_marc_n2 Messages postés 170 Date d'inscription jeudi 11 décembre 2003 Statut Membre Dernière intervention 24 janvier 2009
26 juil. 2006 à 17:00
Hello Santiago,

pas mal du tout tes nouvelles fonctions.

Une remarque concernant Revstring: tu calcules plusieurs fois Len(myString), et en particulier tu le recalcules dans la boucle.
C'est une bonne habitude de précalculer au maximum quand c'est possible.
La fonction peut devenir quelque chose comme ceci:

Function RevString3(ByVal myString As String) As String
Dim i As Long
Dim lg As Long

lg = Len(myString) + 1

'Pre-range answer
RevString3 = Space$(lg)
'Set characters one by one
For i = 1 To lg - 1
Mid$(RevString3, i, 1) = Mid$(myString, lg - i, 1)
Next
End Function

Sur de longues chaines, le gain est non négligeable (10% plus rapide ici, sur une chaine test de 10000 caractères), et c'est de toute façon une bonne habitude.

J'ajouterais qq remarques générales:
- Ajouter (quand c'est possible) Byval/Byref devant les arguments des fonctions, c'est plus agréable à la lecture car la simple lecture du prototype donne toutes les indications sur l'usage des paramètres.
- Ne pas oublier de typer explicitement tous les paramètres des fonctions (quand c'est possible)
- Pour info, lenB() est un poil plus rapide que Len()
- Tester if s=vbNullString est plus rapide que if s=""

Voir à ce sujet un petit bench de mon crû: http://users.skynet.be/candide/benchfunc.htm

Bonne suite :-)
cs_asimengo Messages postés 280 Date d'inscription jeudi 24 mars 2005 Statut Membre Dernière intervention 18 mars 2009
26 juil. 2006 à 14:17
@SANTIAGO69:Pour mieux expliquer ce que je voulais faire consultes cette source que je viens de publier
http://www.vbfrance.com/code.aspx?ID=38798

En gros j'ai écris 3 fonctions:
Public Function InStr2(ByVal sExpression As String, _
ByVal sTexteRecherche As String, _
Optional ByVal lOccurence As Long = 1, _
Optional ByVal lMethodeComparaison As VbCompareMethod = vbTextCompare) As Long
Public Function InStrRev2(ByVal sExpression As String, _
ByVal sTexteRecherche As String, _
Optional ByVal lOccurence As Long = 1, _
Optional ByVal lMethodeComparaison As VbCompareMethod = vbTextCompare) As Long
Public Function ExtraitTexte(ByVal sExpression As String, _
ByVal sDelimiteurGauche As String, ByVal sDelimiteurDroit As String, _
Optional ByVal lSensRecherche As EnumSensRechercheTexte = sr_GaucheVersDroite, _
Optional ByVal lOccurence As Long = 1, _
Optional ByVal lMethodeComparaison As VbCompareMethod = vbTextCompare) As String

Tu constates que j'introduis un paramètre lOccurence (elle indique l'ordre de l'occurence du texte recherché suivant le sens de recherche) qui donne pas mal d'option à ces fonctions

regardes ci-dessous quelques exemples que tu retrouveras d'ailleurs dans ma publication du 26/7/6

ExtraitTexte("ababacx","aba","x",,1)="bac"
ExtraitTexte("ababacx","aba","x",,2)="c"
ExtraitTexte("ababacx","aba","x",,-1)="c"

ExtraitTexte("c:\dos1\dos2\dos3\mabd.mdb","","")="dos1\dos2\dos3\mabd.mdb"
ExtraitTexte("c:\dos1\dos2\dos3\mabd.mdb","","",,-1)="mabd.mdb"
ExtraitTexte("c:\dos1\dos2\dos3\mabd.mdb","","",sr_DroiteVersGauche,-2)="dos1"
ExtraitTexte("c:\dos1\dos2\dos3\mabd.mdb","","",sr_DroiteVersGauche,-3)"dos2"
ExtraitTexte("c:\dos1\dos2\dos3\mabd.mdb","","", sr_GaucheVersDroite ,-2)="dos3"

A+
cs_santiago69 Messages postés 91 Date d'inscription jeudi 18 novembre 2004 Statut Membre Dernière intervention 17 décembre 2008
26 juil. 2006 à 12:23
Salut Asimiengo,

Pour internet, je fais exactement comme precise dans mon message : je me gare au bon endoit. En vrai le plus souvent, je vais

au McDo. Pour trois raisons :
1) On y rentre comme on veut
2) Je peux brancher et recharger mon portable
3) Depuis 6 mois que je voyage en Europe, je n'ai jamais trouve un McDo qui ne soit pas voisin avec un mec qui n'a pas

securise son Wi-Fi (c'est dingue ca !)

Len(Str) = 0
En fait une fois je bossait sur des immenses chaines de texte (elles contenaient des fichiers entier). Et pour les besoins du

programme je devais savoir si la chaine etait vide ou pas.
Or je me suis rendu compte que si on tournait dans une boucle quelques milliers de fois, on gagnait qques secondes en faisant

une comparaison sur la longueur de la chaine plutot que sur son contenu.
J'ai corrige, ca n'a aucun interet ici.



Pour ta fonction, j'ai beaucoup de mal a ecrire quelquechose de general puisque je ne concois toujours pas la portee globale

de ton idee.
1) Soit il s'agit specifiquement de decouper des "Path" et la je ne voit pas ce qu'on peut ajouter que ne propose deja le

"FileSystemObject"
2) Soit on veut recuperer le texte entre 2 borne identiques et la, quel que soit le sens (bRechercheGaucheVersDroite) ou

l'occurence voulue (bRechercheDerniereOccurence), le plus simple me semble l'usage de Split(String, Delimiter)(n)
3) Soit on veut recuperer le texte entre 2 bornes differentes et la :
3.1) probleme1 : le texte renvoye peut-il contenir un autre delimiteur gauche
Extrait de "C:\Mes documents\Santiago.Diez\VB\Mon fichier.log.txt" entre "" et "."
doit il renvoyer "Mes documents\Santiago", "VB\Mon fichier", "Santiago" ou "Mon fichier"
"bRechercheDerniereOccurence" ne me semble pas pertinent : Pourquoi renvoyer "Monfichier" plutot que "Santiago".
De plus attendre la derniere occurence du delimiteur gauche implique d'etre sur que le dernier delimiteur droit est apres le

dernier delimiteur gauche.
"bRechercheGaucheVersDroite" ne me semble pas pertinent non plus : doit on renvoyer "Mon fichier.log" ou "MonFichier" ?
Solution1 : Je propose plutot une option "Stricte" qui impose au texte renvoye de ne contenir aucun delimiteur
3.2) Probleme2 : Quel occurence trouvee doit on renvoyer ?
La premiere semble le plus logique et le plus simple. Un peu a la maniere de la fonction InStr(), on laisse l'utilisateur se

demerder s'il veut renvoyer la n-ieme occurence.
Solution2 : Je propose un parametre "Start" (comme dans InStr())
3.3) Probleme3 : Et si c'est la derniere occurence ?
Dans ce cas, l'utilisateur va devoir lancer des boucles conditionnelles un peu complexes. Alors aidons le a la maniere de la

fonction InStrRev().
Solution3 : Je reviens a ta proposition de depart avec une option de droite a gauche.

Ma nouvelle fonction MidBetween() couvre ces specifications et peut etre adaptee au probleme des "Path".
Debug.Print "Drive is: " & MidBetween("C:\Mes documents\Santiago.Diez\VB\Mon fichier.log.txt", "", "")
Drive is: C:
Debug.Print "Path is: " & MidBetween("C:\Mes documents\Santiago.Diez\VB\Mon fichier.log.txt", "", "", , mbFromTheEnd)
Path is: C:\Mes documents\Santiago.Diez\VB
Debug.Print "Name is: " & MidBetween("C:\Mes documents\Santiago.Diez\VB\Mon fichier.log.txt", "", "", , mbFromTheEnd)
Name is: Mon fichier.log.txt
Debug.Print "Title is: " & MidBetween("C:\Mes documents\Santiago.Diez\VB\Mon fichier.log.txt", "", ".", , mbFromTheEnd)
Title is: Mon fichier.log
Debug.Print "Ext is: " & MidBetween("C:\Mes documents\Santiago.Diez\VB\Mon fichier.log.txt", ".", "", , mbFromTheEnd)
Ext is: txt
Debug.Print "Autre test: " & MidBetween("C:\Mes documents\Santiago.Diez\VB\Mon fichier.log.txt", "", ".", ,

mbStrictlyBetween)
Autre test: Santiago
Debug.Print "Autre test: " & MidBetween("C:\Mes documents\Santiago.Diez\VB\Mon fichier.log.txt", "", ".", ,

mbStrictlyBetween + mbFromTheEnd)
Autre test: Mon fichier

Mon algorithme me semble un peu long, mais c'est le seul moyen que j'ai trouve de repondre a toutes les specifications.



En travailant sur tout ca, j'ai egalement eu l'idee d'une fonction qui va plus loin : SplitBrackets()
L'idee est de faire une fonction qui repose sur deux delimiteurs qui se repondent (tels que des parentheses ou des balises

html). Lorsqu'on extrait une partie du texte, la fonction s'assure que tous les delimiteurs ouvrant sont fermes.
Je reflechis encore aux specification de la fonction.
A priori, la fonction renverais un tableau de 3 elements : la partie a gauche du premier delimiteur ouvrant, la partie entre

2 delimiteurs et la partie a doite du dernier delimiteur fermant.
En utilisant la recursivite, il serait possible de decouper a nouveau chaque sous partie :

Exemple :
Text = "A + (B - C) * (F / (T + G - (T * H)) + D) + H
Decoupage de text: 1 "A + "
2 "B - C"
3 " * (F / (T + G - (T * H)) + D) + H"
Decoupage de 3: 1 " * "
2 "F / (T + G - (T * H)) + D"
3 " + H"
Decoupage de 2: 1 "F / "
2 "T + G - (T * H)"
3 " + D"
Decoupage de 2: 1 "T + G - "
2 "T * H"
3 ""

Le meme genre de decoupage pourrait etre effectue sur une page html

**********************************

Salut Jean-Marc,
J'ai remplace tous les IIf.
cs_asimengo Messages postés 280 Date d'inscription jeudi 24 mars 2005 Statut Membre Dernière intervention 18 mars 2009
12 juil. 2006 à 20:09
'Solution2 : Si jamais ton decoupage ne concerne pas des slash et des points
'Renvoyer le texte entre StrA et StrB
Result = Split(Split(Text, StrA, 2)(1), StrB)(0)

pas mal pensé, je l'aime bien cette approche, super SANTIAGO69.

A+
cs_asimengo Messages postés 280 Date d'inscription jeudi 24 mars 2005 Statut Membre Dernière intervention 18 mars 2009
12 juil. 2006 à 20:02
juste un truc SANTIAGO69 si tu n'as pas accès à internet cmt fais tu pour publier tes sources?

Autre chose pourquoi à chaque fois tu fais len(string)=0 au lieu de string=""?

Quand à la fonction j'enonce sa définition tel que moi je l'ai écris :
Public function ExtraitTexte(sExpression as string, sDelimiteurGauche as string, sDelimiteurDroite as string, optional bRechercheGaucheVersDroite as boolean true, optional bRechercheDerniereOccurence as boolean true) as string

Tel que définit pas besoin de gestion d'erreur parce qu'aucune combinaison de paramètres n'est incohérente donc il retourne simplement un texte vide si la recherche n'est pas fructueuse.
Pour ma part si bRechercheGaucheVersDroite = True alors bRechercheDerniereOccurence s'applique au délimiteur gauche sinon il s'applique au délimiteur droite.

exemple soit st="c:\mes documents\mabd.mdb"
ExtraitTexte(st, "","") retoune "mabd.mdb" ou ExtraitTexte(st, "","", false) retoune également "mabd.mdb"

ExtraitTexte(st, "","",true ,false) retoune "mes documents" et ExtraitTexte(st, "","",,true) retourne une chaine vide.

ExtraitTexte(st, "",":") retourne "c"

Là on remarque que si le démiteur ="" alors le paramètre bRechercheDerniereOccurence ne joue aucun rôle.

ça me plairait bien que tu écrives cette fonction afin que je compare les algorithmes, je pense que ça pourra m'apporter un plus.

Peut-être as tu d'autres développement de cette fonction qui permettrait encore plus de choses sans qu'elle ne perde de sa simplicité.

A+
cs_santiago69 Messages postés 91 Date d'inscription jeudi 18 novembre 2004 Statut Membre Dernière intervention 17 décembre 2008
12 juil. 2006 à 17:58
je viens de poster la version 2.0
cs_santiago69 Messages postés 91 Date d'inscription jeudi 18 novembre 2004 Statut Membre Dernière intervention 17 décembre 2008
12 juil. 2006 à 17:53
Salut Asimiengo,
Pour ton exercice j'envisage plutot 2 solutions alternatives :

'Solution1 : Le FileSystemObject
'Fonctionne meme sur des chemins inexistants
'Execute ce code pour bien comprendre chaque fonction
Dim FSO As Object
Set FSO = CreateObject("Scripting.FileSystemObject")
MsgBox FSO.GetBaseName("C:\Dossier\Fichier.txt")
MsgBox FSO.GetExtensionName("C:\Dossier\Fichier.txt")
MsgBox FSO.GetFileName("C:\Dossier\Fichier.txt")
MsgBox FSO.GetParentFolderName("C:\Dossier\Fichier.txt")
MsgBox FSO.GetFileName(FSO.GetParentFolderName("C:\Dossier\Fichier.txt"))
'Pas mal non ;o)

'Solution2 : Si jamais ton decoupage ne concerne pas des slash et des points
'Renvoyer le texte entre StrA et StrB
Result = Split(Split(Text, StrA, 2)(1), StrB)(0)

La solution 2 peut etre ajoutee a mon module, mais j'aime les choses bien faites, il faudrait que nous statuions ensemble sur le comportement de la fonction en cas d'erreur.
Pour la premiere fois je vais mettre 2 noms dans le copyright d'un module.

Desole pour RegExp, on a du mal a croire qu'en 2006 un membre de vbfrance n'ai pas internet. Enfin si, il suffit que je gare mon camping-car dans la bonne rue a Istanbul et je choppe un wi-fi. Merci de m'avoir mache le travail.

********************************

Salut Jean-Marc,
Merci pour ton conseil.

********************************

Salut Joro,
Merci pour ton compliment.
Je suis espagnol, j'ai majoritairement vecu en France, aujourd'hui je suis nomade : La belle vie de par le monde.
Je commente en anglais parceque :
- http://www.vbfrance.com/auteurdetail.aspx?ID=383011
- http://www.vbfrance.com/code.aspx?ID=38468

********************************

Merci a tous
Santiago
cs_joro Messages postés 71 Date d'inscription vendredi 24 janvier 2003 Statut Membre Dernière intervention 21 septembre 2007
11 juil. 2006 à 10:27
J'aime bien tes sources "santiago69" mais pourquoi les commenter en anglais.
Est-ce un exercice de style ou bien es-tu anglais ?
jean_marc_n2 Messages postés 170 Date d'inscription jeudi 11 décembre 2003 Statut Membre Dernière intervention 24 janvier 2009
10 juil. 2006 à 20:01
Hello,

sympathique et bien codé. Une petite information: la fonction IIF(...) est très (mais alors TRES, TRES) lente, si tu as besoin de performances, il vaut mieux l'éviter.

Bonne suite!
cs_asimengo Messages postés 280 Date d'inscription jeudi 24 mars 2005 Statut Membre Dernière intervention 18 mars 2009
10 juil. 2006 à 17:14
je prends un texte comme "c:\mes documents\mabd.mdb", la fonction que je propose servirait à extraire le mot mabd.mdb dans le texte avec comme délimiteur gauche "" et comme délimiteur droite "". suivant que le sens de la recherche est indiqué gauche vers droite il faut préciser à la fonction de considérer la dernière occurence de "", par contre si la sens de la recherche est de droite vers gauche, l'option première occurence ou dernière occurence s'appliquera à "",enfin c'est juste une proposition.

Concernant RegExp, même sur vbfrance en faisant une recherche sur regex tu tompes sur de nombreux codes parlant de ça. Sinon tu peux consulter cette page http://cafeine.developpez.com/access/tutoriel/regexp/ c'est avec ce tuto que moi même j'ai pu bien appréhencer ce que c'était que RegExp(Microsoft VBScript Regular Expressions n.n).

Bonne Prog.
cs_santiago69 Messages postés 91 Date d'inscription jeudi 18 novembre 2004 Statut Membre Dernière intervention 17 décembre 2008
9 juil. 2006 à 16:55
Salut Asimengo,
Merci pour ton commentaire. Je ne vois pas bien de quoi tu parle avec ta fonction d'extraction de texte. Peux tu donner un exemple ?
J'ai cherche RegExp, mais elle n'est pas proposee dans la liste des references possibles de mon VB, peux tu me dire ou la trouver.
Santiago
cs_santiago69 Messages postés 91 Date d'inscription jeudi 18 novembre 2004 Statut Membre Dernière intervention 17 décembre 2008
9 juil. 2006 à 16:54
Salut Asimengo,
Merci pour ton commentaire. Je ne vois pas bien de quoi tu parle avec ta fonction d'extraction de texte. Peux tu donner un exemple ?
J'ai cherche RegExp, mais elle n'est pas proposee dans la liste des references possibles de mon VB, peux tu me dire ou la trouver.
Santiago
cs_asimengo Messages postés 280 Date d'inscription jeudi 24 mars 2005 Statut Membre Dernière intervention 18 mars 2009
7 juil. 2006 à 12:52
Interessant.

Vu que tu fais dans les fonctions d'extraction de texte, il serait interessant d'ajouter une fonction qui renvoie le texte entre 2 bornes textes, avec comme autre paramètre le sens de la recherche(de gauche vers droite ou de droite vers gauche) et un paramètre pour spécifier s'il faut considérer la première occurence ou la dernière. C'est une fonction à mon avis très utile qui servirait à beaucoup.

D'autre part grâce à l'aide de Troxsa j'ai fais connaissance avec RegExp (c'est une DLL Microsoft Script Regular Expressions 5.0) qui est vraiment le top pour les extractions de texte, je t'invite à y faire un tour.

A+
Rejoignez-nous