Question expression régulieres

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
cage
Messages : 604
Inscription : ven. 16/oct./2015 18:22
Localisation : France
Contact :

Question expression régulieres

Message par cage »

Bonsoir a tous,

Encore un domaine où j'ai beaucoup de lacunes.

Dans la lecture d'un fichier ligne a ligne, je voudrais pouvoir détecter si la ligne contient certains motifs tels que:
une suite de 3 # --> ###
une suite de 3 * --> ***
une suite de 3 + --> +++
une suite de 3 - --> ---
une suite de 3 = --> ===
une suite égale a - -
J'ai écris cette expression régulière qui fais bien le travail, mais je ne suis pas sur que ce soit la meilleure façon de faire.
Une âme charitable pourrait-elle me dire si j'ai bon ou s'il y a une meilleure façon de faire.
Merci d'avance.
cage
Voici la solution que j'ai trouvé dans ce bout de code

Code : Tout sélectionner

EnableExplicit

Define NewMap chaine.s(),N,texte$

chaine("1") = "Chaine1 : Tester si 3 *** dans la chaine."
chaine("2") = "Chaine2 : Tester si 3 ### dans la chaine."
chaine("3") = "Chaine3 : Tester si 3 === dans la chaine."
chaine("4") = "Chaine4 : Tester si 3 +++ dans la chaine."
chaine("5") = "Chaine5 : Tester si 3 --- dans la chaine."
chaine("6") = "Chaine6 : Tester si 3 - - dans la chaine."
chaine("7") = "Chaine7 : Cette chaine"

Define regex=CreateRegularExpression(#PB_Any, "([*]{3}|[#]{3}|[=]{3}|[-]{3}|[+]{3}|- -)")

For N=1 To 7
  texte$=chaine(Str(N))
  If regex
    If ExamineRegularExpression(regex, texte$)
      If NextRegularExpressionMatch(regex)
        Debug texte$
      Else
        Debug chaine(Str(N))+" ne contient aucun des motifs."
      EndIf
    EndIf
  Else
    
  EndIf
Next
FreeRegularExpression(regex)
■ Win10 Pro 64-bit (Intel Celeron CPU N2920 @ 1.86GHz, 4,0GB RAM, Intel HD Graphics) & PB 6.12 LTS
■ Vivre et laisser vivre.
■ PureBasic pour le fun
■ Gérard sur le forum Anglais
■ Mes sites: http://pbcage.free.fr - http://yh.toolbox.free.fr
boddhi
Messages : 604
Inscription : lun. 26/avr./2010 16:14
Localisation : S 48° 52' 31'' / O 123° 23' 33''

Re: Question expression régulieres

Message par boddhi »

Ton code a l'air de satisfaire ton attente mais sans exemples précis de chaînes que tu as à traiter, il est difficile de dire s'il peut être fait mieux.
La contrainte peut-elle être trouvée à un endroit qui n'est pas celui attendu ?
Doit-il y avoir une seule contrainte par chaîne ?
Avatar de l’utilisateur
cage
Messages : 604
Inscription : ven. 16/oct./2015 18:22
Localisation : France
Contact :

Re: Question expression régulieres

Message par cage »

Il n'y a aucune contrainte particulière a la recherche.
Ça doit 'matcher' si au moins un des motifs "###", "***", "===",... est contenu dans la chaine.
Le motif est une chaine d'au mois 3 caractères, ce qui veut dire que "===" ou "==============" ou "=== ###" "matchent".

Ma question porte plutôt sur la façon d'écrire un motif, par exemple quel motif décrit le mieux 3 caractères "=" qui se suivent.
Pour moi, [=]{3} signifie la répétition de 3 caractères "="

Pour moi, [.]{3} signifie la répétition de 3 caractères "." tout en enlevant la signification du point "." qui peut représenter n'importe quel caractère.

Il y-a-t-il une autre façon plus efficace d'écrire ce motif.
cage
■ Win10 Pro 64-bit (Intel Celeron CPU N2920 @ 1.86GHz, 4,0GB RAM, Intel HD Graphics) & PB 6.12 LTS
■ Vivre et laisser vivre.
■ PureBasic pour le fun
■ Gérard sur le forum Anglais
■ Mes sites: http://pbcage.free.fr - http://yh.toolbox.free.fr
Marc56
Messages : 2197
Inscription : sam. 08/févr./2014 15:19

Re: Question expression régulieres

Message par Marc56 »

Bonsoir,

ou ça:

Code : Tout sélectionner

"(?:\*|#|=|\+|-){3}|- -")
Seul * et + ont besoin d'\

Mais bon, pour du texte fixe, autant utiliser FindString()
:wink:
boddhi
Messages : 604
Inscription : lun. 26/avr./2010 16:14
Localisation : S 48° 52' 31'' / O 123° 23' 33''

Re: Question expression régulieres

Message par boddhi »

Tout comme dans d'autres langages, certains caractères/symboles/signes sont dits 'spéciaux' et ont une signification/fonction précise. Le '.' en regex en fait partie comme tu le sais.

Donc, pour pouvoir les considérer comme caractères normaux, il te faut recourir au caractère (dit d'échappement) '\' .

Ainsi, si tu veux qu'un point soit reconnu dans un regex, tu devras écrire '\.' donc '\.{3}' recherchera '...' dans ta chaîne de caractères (Bien-sûr ne pas tenir compte des apostrophes présents dans mes exemples :wink: )
De même, si tu recherches le caractère '\' dans une chaîne, tu devras l'annoter '\\' dans ta regex.

Edit : @Marc, tu as rédigé ta réponse plus rapidement que moi, du coup certains éléments de la mienne sont redondants :wink:
boddhi
Messages : 604
Inscription : lun. 26/avr./2010 16:14
Localisation : S 48° 52' 31'' / O 123° 23' 33''

Re: Question expression régulieres

Message par boddhi »

@Marc,
Marc56 a écrit : Mais bon, pour du texte fixe, autant utiliser FindString()
Question technique : Selon toi, quand tu as une dizaine de FindString() à effectuer pour rechercher une dizaine de chaînes de caractères à la suite, un peu comme dans le cas de cage, pour des chaînes très longues, quelle est la solution la plus rapide : FindString() ou une Regex ? La question vaut aussi pour ReplaceString()...
Avatar de l’utilisateur
cage
Messages : 604
Inscription : ven. 16/oct./2015 18:22
Localisation : France
Contact :

Re: Question expression régulieres

Message par cage »

Bonsoir,
Tiré de la doc, je site:
CreateRegularExpression()

Syntax

Result = CreateRegularExpression(#RegularExpression, Pattern$ [, Flags])
Description

Create a new regular expression using the specified pattern.
Parameters

#RegularExpression A number to identify the new regular expression. #PB_Any can be used to auto-generate this number.
Pattern$ The regular expression which will be applied to the string to match, extract or replace.
Flags (optional) It can be a combination of the following values:
#PB_RegularExpression_DotAll : '.' matches anything including newlines.
#PB_RegularExpression_Extended : whitespace and '#' comments will be ignored.
#PB_RegularExpression_MultiLine : '^' and '$' match newlines within data.
#PB_RegularExpression_AnyNewLine: recognize 'CR', 'LF', and 'CRLF' as newline sequences.
#PB_RegularExpression_NoCase : comparison and matching will be case-insensitive
Donc, dans un regex PB, inutile de protéger '.' par '\."
@Marc56,
Mais bon, pour du texte fixe, autant utiliser FindString()
Dans mon cas, non. J'ai testé avec FindString() et regex, il n'y a pas photo.
Le traitement par regex est beaucoup plus rapide et simple a écrire.
Un exemple de ce que je faisais avec FindString() et maintenant avec un regex

Code : Tout sélectionner

If FindString(entry$,"---") Or
   FindString(entry$,"***") Or
   FindString(entry$,"===") Or
   FindString(entry$,"+++") Or
   FindString(entry$,"###") Or
   FindString(entry$,"- -") Or
   FindString(entry$,"...")
J'ai testé avec
ou ça:

"(?:\*|#|=|\+|-){3}|- -")

Plain text
Seul * et + ont besoin d'\
C'est Ok pour moi, écriture plus condensée.
Je commence a fatiguer, donc je crois que je vais en rester là pour ce soir.
Bonne nuit a tous,
cage
■ Win10 Pro 64-bit (Intel Celeron CPU N2920 @ 1.86GHz, 4,0GB RAM, Intel HD Graphics) & PB 6.12 LTS
■ Vivre et laisser vivre.
■ PureBasic pour le fun
■ Gérard sur le forum Anglais
■ Mes sites: http://pbcage.free.fr - http://yh.toolbox.free.fr
boddhi
Messages : 604
Inscription : lun. 26/avr./2010 16:14
Localisation : S 48° 52' 31'' / O 123° 23' 33''

Re: Question expression régulieres

Message par boddhi »

cage a écrit : Donc, dans un regex PB, inutile de protéger '.' par '\."
En es-tu si certain ?

Code : Tout sélectionner

RegEx=CreateRegularExpression(0,".",#PB_RegularExpression_DotAll)
Debug MatchRegularExpression(0,"C:\Fichier") ; Il n'y a pas de point et pourtant il y a bien un retour positif !!!
Debug MatchRegularExpression(0,"C:\Fichier.txt")
FreeRegularExpression(0)
RegEx=CreateRegularExpression(0,"\.",#PB_RegularExpression_DotAll)
Debug MatchRegularExpression(0,"C:\Fichier")
Debug MatchRegularExpression(0,"C:\Fichier.txt")
EDIT : Ajout du code suivant :

Code : Tout sélectionner

RegEx=CreateRegularExpression(0,".{3}",#PB_RegularExpression_DotAll)
Debug MatchRegularExpression(0,"C:\Fichier..")
Debug MatchRegularExpression(0,"C:\Fichier.txt")
Debug MatchRegularExpression(0,"C:\Fichier...txt")
FreeRegularExpression(0)
RegEx=CreateRegularExpression(0,"\.{3}",#PB_RegularExpression_DotAll)
Debug MatchRegularExpression(0,"C:\Fichier")
Debug MatchRegularExpression(0,"C:\Fichier.txt")
Debug MatchRegularExpression(0,"C:\Fichier...txt")
Marc56
Messages : 2197
Inscription : sam. 08/févr./2014 15:19

Re: Question expression régulieres

Message par Marc56 »

Le point (dot) en langage Expressions Régulière signifie tous les caractères SAUF le saut de ligne.
Raison historique des anciens programmes qui analysaient ligne par ligne.
Explication ici
Donc on a un paramètre pour indiquer si on veut que le saut de ligne (CR, LF (\n \r)) soit considéré comme n'importe quel caractère. (et le saut de ligne est différent Windows, Linux, Mac)

Utiliser les expression régulières ou la recherche en texte ne doit pas changer grand chose sur des petits fichiers. On n'est pas à quelques millisecondes près, donc on privilégie la lisibilité pour la facilité de maintenance. Si on a des milliers, millions de lignes, on teste avant.

Les regex sont intéressantes voir plus simples quand on a des données variables (ex: numéros de téléphone, adresses mails) ou des données balisées pas toujours collées (ex: Facture: <des caractères> des chiffres)
Avatar de l’utilisateur
cage
Messages : 604
Inscription : ven. 16/oct./2015 18:22
Localisation : France
Contact :

Re: Question expression régulieres

Message par cage »

Bonjour,

@boddhi,
J'ai repris ton code et je l'ai modifié, histoire d'y voir plus clair.

Code : Tout sélectionner

Declare Tester(RegEx,t$)
OpenConsole()
ConsoleColor(15,0)
RegEx=CreateRegularExpression(#PB_Any,".{3}")
Tester(RegEx,"C:\Fichier..")
Tester(RegEx,"C:\Fichier.txt")
Tester(RegEx,"C:\Fichier...txt")
FreeRegularExpression(RegEx)
PrintN(RSet("",30,"-"))

RegEx=CreateRegularExpression(#PB_Any,"[.]{3}")
Tester(RegEx,"C:\Fichier..")
Tester(RegEx,"C:\Fichier.txt")
Tester(RegEx,"C:\Fichier...txt")
FreeRegularExpression(RegEx)
PrintN(RSet("",30,"-"))

RegEx=CreateRegularExpression(#PB_Any,"\.{3}")
Tester(RegEx,"C:\Fichier..")
Tester(RegEx,"C:\Fichier.txt")
Tester(RegEx,"C:\Fichier...txt")
FreeRegularExpression(RegEx)
PrintN(RSet("",30,"-"))

Input()
CloseConsole()

Procedure Tester(RegEx,t$)
  result$="faux"
  If RegEx
    result=MatchRegularExpression(RegEx,t$)
    If result:result$="trouvé":EndIf
    If ExamineRegularExpression(RegEx, t$)
      If NextRegularExpressionMatch(RegEx)
        match$=RegularExpressionMatchString(RegEx)
        PrintN("résultat sur "+t$+ " : "+result$+" "+match$)
      Else
        PrintN("résultat : "+result$)
      EndIf
    EndIf
  EndIf
EndProcedure
Le flag #PB_RegularExpression_DotAll ne semble pas fonctionner comme attendu.
Conclusion:
L'expression ".{3}" trouve tout et n'importe quoi avec ou sans le flag
L'expression "\.{3}" trouve bien trois points qui se suivent
L'expression "[.]{3}" trouve bien trois points qui se suivent
Voici le résultat obtenu en exécutant le code

Code : Tout sélectionner

résultat sur C:\Fichier.. : trouvé C:\
résultat sur C:\Fichier.txt : trouvé C:\
résultat sur C:\Fichier...txt : trouvé C:\
------------------------------
résultat : faux
résultat : faux
résultat sur C:\Fichier...txt : trouvé ...
------------------------------
résultat : faux
résultat : faux
résultat sur C:\Fichier...txt : trouvé ...
------------------------------
Merci a vous deux (boddhi et Marc56) pour vos informations très précieuses.
cage
■ Win10 Pro 64-bit (Intel Celeron CPU N2920 @ 1.86GHz, 4,0GB RAM, Intel HD Graphics) & PB 6.12 LTS
■ Vivre et laisser vivre.
■ PureBasic pour le fun
■ Gérard sur le forum Anglais
■ Mes sites: http://pbcage.free.fr - http://yh.toolbox.free.fr
Répondre