Page 1 sur 2
[..] Avoir tous les résultats avec StringRegExp
Posté : sam. 06 sept. 2008 14:12
par tolf
Bonjour,
Dans mon script j'utilise une chaîne de caractères contenant de virgules et je voudrais séparer la chaîne suivant les virgules donc pour le moment pas de problème :
seulement voilà je ne voudrais pas que les virgules servent de séparateur quand elles sont entre des guillemets. Je pense donc que la fonction StringRegExp est tout à fait appropriée et voici mon code :
Code : Tout sélectionner
#include <Array.au3>
$resultat = StringRegExp('salut, "bonjour, comment allez vous ?", #00ffff, 354', '[^,"]*("[^"]*")*[^,"]*', 3)
_ArrayDisplay($resultat)
Problème : la table $resultat ne contient que '
salut' alors que je voudrais qu'elle contienne :
salut
"bonjour, comment allez vous ?"
#00ffff
354
a priori, le flag 3 correspond à des résultats globaux donc comment faire ?
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : sam. 06 sept. 2008 20:43
par moutelous
Bonjour tolf,
Pour ma part je m'attends également à trouver toutes les occurrences avec le flag 3, curieux ... avec les quelques tests effectués de mon côté le global s'arrête dès le premier caractère qui ne "match" pas ...
Une petite recherche supplémentaire s'impose ...
A+
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : sam. 06 sept. 2008 21:46
par sylvanie
Bonsoir, l'expression n'est pas bien adaptée :
[^,"]*("[^"]*")*[^,"]*
salut, "bonjour, comment allez vous ?", #00ffff, 354
salut vat matcher avec [^,"]*
mais le reste de la chaîne suivant salut est : ', "bonjour, comment allez vous ?", #00ffff, 354'
et doc à cause de ', ' on s'arrête
pour rendre la recherche générique, on doit donc sélectionner :
tout ce qui ne comporte pas de , ni de "
ou
tout ce qui est de la forme "......."
ie
([^,"]+)
|
(".*")
les () sont très importantes, car elles forcent le regroupement
d'où au final :
Code : Tout sélectionner
#include <Array.au3>
$resultat = StringRegExp('salut, "bonjour, comment allez vous ?", #00ffff, 354', '([^,"]+)|(".*")', 3)
_ArrayDisplay($resultat)
cependant, une lacune dans cette dernière expression persiste : des lignes retournées vide (espaces ?) en trops, d'où un second traitement à faire après pour les éliminer en attendant de poffiner l'expression :
[0]|salut
[1]|
[2]|
[3]|"bonjour, comment allez vous ?"
[4]| #00ffff
[5]| 354
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : sam. 06 sept. 2008 22:47
par moutelous
Re ....
En fait l'expression de Tolf est la bonne à un caractère près :
Cette expression match correctement (sous autoit) :
A+
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : sam. 06 sept. 2008 23:35
par sylvanie
bien vu,
d'ailleurs celle-ci du coups suffit :
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : dim. 07 sept. 2008 00:17
par moutelous
Ouaip ...
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : dim. 07 sept. 2008 00:49
par Tlem
Trop fort les expressions régulières.
Je vous envie de les maitriser.
Sylvanie, un explication détaillée de la dernière solution serait très apprécié.

Re: [..] Avoir tous les résultats avec StringRegExp
Posté : dim. 07 sept. 2008 13:22
par tolf
Tlem a écrit :Trop fort les expressions régulières.
Je vous envie de les maitriser.
J'ai (presque complètement) traduit le fichier texte correspondant à la fonction
ici et je pense qu'il serait utile de générer le fichier html et de le mettre sur le forum.
Tlem a écrit :Sylvanie, un explication détaillée de la dernière solution serait très apprécié.
signifie :
-
[^,"] tout caractère autre que virgule et guillemet double
-
+ répété 1 ou plusieurs fois
-
("[^"]*") un groupe composé d'un guillemet, puis de tout caractère autre que guillemet répété autant de fois que nécessaire, puis d'un guillemet
-
* ce groupe étant répété autant de fois que nécessaire
Re: [R] Avoir tous les résultats avec StringRegExp
Posté : dim. 07 sept. 2008 16:33
par sylvanie
voilà une joile explication, rien à ajouter...
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : dim. 07 sept. 2008 16:54
par tolf
oui mais petit problème : si je ne mets pas d'espace après la virgule aïe aïe aïe

voici le résultat :
chaîne :
Code : Tout sélectionner
'salut,"bonjour, comment allez vous ?","moi, je vais bien",#00ffff,354'
résultat :
Code : Tout sélectionner
[0]salut
[1]bonjour
[2]","
[3]moi
[4] je vais bien
[5]#00ffff
[6]354

Re: [..] Avoir tous les résultats avec StringRegExp
Posté : dim. 07 sept. 2008 17:33
par tolf
ceci est sans doute dû au fait que le premier caractère (
[^,"] = tout caractère autre que virgule et guillemet) doit pouvoir exister en 0 fois (comme au début).
Donc en fait, je pense que le bug du début était dû au fait qu'une chaîne vide correspondait au pattern (car * peut valoir "existant 0 fois").
Donc raisonnons autrement. Le pattern est composé de
[^,"] et de
("[^"]*"). Il faut faire figurer les cas de figure suivants :
- le 1er existant 0 fois et le 2ème au moins une fois (pour éviter la chaîne vide) :
("[^"]*")+
- le 1er existant 1 fois ou plus et le 2ème 0 fois :
[^,"]+
- les deux existant 1 fois ou plus :
[^,"]+("[^"]*")+
donc, en rassemblant les 3 par des
|, ça fait le pattern suivant :
(("[^"]*")+)|([^,"]+)|([^,"]+("[^"]*")+)
mais il y a des répétition dans les résultats dans ce cas

Re: [..] Avoir tous les résultats avec StringRegExp
Posté : dim. 07 sept. 2008 22:25
par Tlem
Les expressions régulières sont souvent très commode pour retrouver un résultat en très peut de ligne de code, mais parfois ce n'est pas si simple et le temps de trouver le bon Pattern on à plus vite fait de faire une fonction simple.
Donc comme je suis mauvais en expressions régulières

, je vais proposer une alternative plutôt basique, mais fonctionnelle.
► Afficher le texteDécomposition d'une chaîne
Code : Tout sélectionner
#include <Array.au3>
Dim $Chaine = 'salut,"bonjour, comment allez vous ?","moi, je vais bien",#00ffff,354'
; Utilisation de la fonction.
$aChaine = _StringDecomp($Chaine)
; Résultat.
_ArrayDisplay($aChaine, "Resultat")
; La fonction qui décompose.
Func _StringDecomp($Str)
Local $Flag = 0, $Res
; Boucle pour lire la chaîne, caractère par caractère.
For $i = 1 To StringLen($Str)
$Var = StringMid($Str, $i, 1)
; On va utiliser un commutateur pour savoir
; si on est dans une chaîne entre guillemet ou non.
If $Var = '"' Then
If $Flag = 1 Then
$Flag = 0
Else
$Flag = 1
EndIf
EndIf
; Traitement des différents cas de la virgule.
; Hors "", dans ""
If $Var = ',' Then
If $Flag = 0 Then
$Res &= '|'
Else
$Res &= ','
EndIf
Else
; Sinon écriture du caractère
$Res &= $Var
EndIf
Next
; On retourne un tableau.
Return StringSplit($Res, "|")
EndFunc ;==>_StringDecomp
Je pense qu'avec un
StringRegExpReplace pour remplacer les virgules hors "" par un | puis un
StringRegExp du résultat ce serait plus simple.
A vous Tolf et Sylvanie ...

Re: [..] Avoir tous les résultats avec StringRegExp
Posté : dim. 07 sept. 2008 23:24
par moutelous
Bonjour,
Tlem a écrit :Les expressions régulières sont souvent très commode pour retrouver un résultat en très peut de ligne de code, mais parfois ce n'est pas si simple et le temps de trouver le bon Pattern on à plus vite fait de faire une fonction simple.

Mais si, mais si ....
Essayez donc ceci :
A+
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : lun. 08 sept. 2008 00:06
par Tlem
Ha vi, ça fonctionne rudement bien (screugneugneu

)
Manque plus que les explications.

Re: [..] Avoir tous les résultats avec StringRegExp
Posté : lun. 08 sept. 2008 00:23
par moutelous
Tlem a écrit :Manque plus que les explications.

[^,"\s]+ : match avec tout caractère autre que , " ou forme d'espace (\s), répété 1 ou plusieurs fois
|: ou
("[^"]*") :match avec un groupe formé d'un " suivi de tout caractère répété 0 ou plusieurs fois autre qu'un guillemet et terminé par un "
Vouala
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : lun. 08 sept. 2008 18:41
par sylvanie
le pb du \s est qu'il va splitter les mots entre 2 , :
exple :
Code : Tout sélectionner
$resultat = StringRegExp('salut tout le monde,"bonjour, comment allez vous ?","moi, je vais bien",#00ffff,354', '[^,"\s]+|("[^"]*")', 3)
[0]|salut
[1]|tout
[2]|le
[3]|monde
[4]|"bonjour, comment allez vous ?"
[5]|"moi, je vais bien"
[6]|#00ffff
[7]|354
Et si on l'enlève, ça marche , mais on revient à l'expression où il faut dans certains cas écrèmer les lignes "vides" en trops ...
faut voir si dans le besoins initial de Tolf, on peut être dans ce cas de figure.
il est intéressant ce cas ...
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : lun. 08 sept. 2008 20:37
par moutelous
Ah ! ben NON
Une des règles majeur du REGEX est d'étudier le fichier à exploiter, je suis donc parti du postulat qu'entre les virgules il n'existe qu'un seul terme (sans espace), si virgule(s) et donc espace(s) existent, c'est une phrase , qui doit donc être mise entre guillemet ! (sinon pourquoi cette différence ?)
Dans ce sens le pattern proposé match bien avec le besoin initial de Tolf .......
Mais bon, on peut changer les règles du jeu, soyons joueur

et essayons d'inclure ces espaces ...
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : lun. 08 sept. 2008 21:00
par tolf
Bon j'ai opté pour la solution de Tlem qui est en fait très bien (j'avais juste un peu la flemme de faire une telle fonction au début en croyant que StringRegExp diminuerait la taille de mon code mais en fait ça me prend plus de temps

).
J'ai juste un petit peu modifié le code pour que s'il y a un '|' déjà existant, il ne serve pas de séparateur :
► Afficher le texteDécomposition de chaîne modifié
Code : Tout sélectionner
#include <Array.au3>
$Chaine = 'salut,"bonjour, comment allez vous ?" mots hors citation "ceci est la suite de bonjour,...","moi, je vais bien",#00ffff,354,\v marque une virgule de séparation, ce "|" ne sert pas de séparation'
; Utilisation de la fonction.
$aChaine = _StringDecomp($Chaine)
; Résultat : séparateur "&" pour l'affichage de _ArrayDisplay
_ArrayDisplay($aChaine, "Resultat", -1, 0, "&")
; La fonction qui décompose.
Func _StringDecomp($Str)
Local $Flag = 0, $Res, $aSplit, $i, $Var
; Boucle pour lire la chaîne, caractère par caractère.
For $i = 1 To StringLen($Str)
$Var = StringMid($Str, $i, 1)
; On va utiliser un commutateur pour savoir
; si on est dans une chaîne entre guillemet ou non.
If $Var = '"' Then
If $Flag = 1 Then
$Flag = 0
Else
$Flag = 1
EndIf
EndIf
; Traitement des différents cas de la virgule.
; Hors "", dans ""
If $Var = ',' And $Flag = 0 Then
$Res &= [color=#FF4000]'\v'[/color]
[color=#FF0000]ElseIf $Var = "\" Then
$Res &= '\b'[/color]
Else
; Sinon écriture du caractère
$Res &= $Var
EndIf
Next
; On retourne un tableau.
$aSplit = StringSplit($Res, [color=#FF0000]'\v'[/color], 1)
[color=#FF0000]For $i = 1 To $aSplit [0]
$aSplit [$i] = StringReplace($aSplit [$i], '\b', '\')
Next[/color]
Return $aSplit
EndFunc ;==>_StringDecomp
Par contre, j'aimerais bien connaître la solution avec StringRegExp (car elle doit sûrement exister celle-là

) car elle doit être très intéressante.
Re: [..] Avoir tous les résultats avec StringRegExp
Posté : lun. 08 sept. 2008 21:09
par Tlem
J'ai pas trop compris la remarque de Sylvanie, car ce pattern
[^,"\s]+|("[^"]*") crée bien le tableau comme le souhaite tolf :
Code : Tout sélectionner
[0] salut
[1] "bonjour, comment allez vous ?"
[2] "moi, je vais bien"
[3] #00ffff
[4] 354
et non le résultat présenté par Sylvanie.

Re: [..] Avoir tous les résultats avec StringRegExp
Posté : lun. 08 sept. 2008 21:21
par Tlem
@tolf vous pouvez vous simplifier la vie en utilisant comme séparateur une suite de symboles improbable (genre
~#~) et modifier la fonction StringSplit en mettant le flag à 1.
J'ai vu ça en lisant la doc, et ça m'a permis de voir que StringSplit peut splitter une chaîne sur plusieurs caractères en même temps.
