Règle des signes

Aide et conseils concernant AutoIt et ses outils.
Règles du forum
.
mdanielm
Membre émérite
Membre émérite
Messages : 254
Enregistré le : mer. 11 déc. 2013 19:48
Status : Hors ligne

Règle des signes

#1

Message par mdanielm »

Bonjour,
Je recherche une regex, une seule, qui en une passe seulement remplace des séries de signes +, -, par un seul signe, en respectant la règle des signes:

+- ou -+ donne -
-- ou ++ donne +

Bref, une meilleure solution que la solution naïve suivante:
$in = "++-+3---5++(2*-+3)+-1"
Signe($in)
ConsoleWrite($in & @crlf)

func Signe(byref $in)
   local $n
   do
      $in = StringRegExpReplace($in,"\+-|-\+", "-")
      $n=@extended
      $in = StringRegExpReplace($in,"\+\+|--", "+")
      $n+=@extended
      ;ConsoleWrite($n & @crlf)
   until $n=0
EndFunc
Modifié en dernier par mdanielm le mar. 19 mai 2020 14:30, modifié 3 fois.
Avatar du membre
TommyDDR
Modérateur
Modérateur
Messages : 2086
Enregistré le : mar. 22 juil. 2008 21:55
Localisation : Nantes
Status : Hors ligne

Re: Règle des signes

#2

Message par TommyDDR »

Comme dans cette règle, le "+" n'a aucune incidence, et seul un nombre pair de "-" donnent un "+", vous pouvez faire de la sorte :
Global $in = "++-+---+++-"
Signe($in)
ConsoleWrite($in & @crlf)

func Signe(byref $in)
   Local $temp = StringReplace($in, "+", "") ; On supprime les + car inutiles pour définir si on a un + ou un -
   Local $countMinus = StringLen($in) ; On compte les - restants
   $in = Mod($countMinus, 2) == 0 ? "+" : "-" ;Si on en a un nombre pair, on met un +, sinon, on met un -
EndFunc
Ce code fonctionne bien entendu que si vous fournissez une chaine avec seulement des + et des -, pas d'autre caractères, je vous laisse adapter le code si jamais vous avez besoin d'envoyer autre chose en plus.
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
Avatar du membre
mikell
Spammer !
Spammer !
Messages : 6292
Enregistré le : dim. 29 mai 2011 17:32
Localisation : Deep Cévennes
Status : Hors ligne

Re: Règle des signes

#3

Message par mikell »

func Signe(byref $in)
   StringReplace($in, "-", "yo!")
   $in = Mod(@extended, 2) == 0 ? "+" : "-" ;Si on en a un nombre pair, on met un +, sinon, on met un -
EndFunc
:mrgreen:
" L'échec est le fondement de la réussite. " (Lao-Tseu )
" Plus ça rate, plus on a de chances que ça marche " (les Shadoks )
mdanielm
Membre émérite
Membre émérite
Messages : 254
Enregistré le : mer. 11 déc. 2013 19:48
Status : Hors ligne

Re: Règle des signes

#4

Message par mdanielm »

J'ai édité le message d'origine car dans ma chaîne il y a d'autres caractères!
Avatar du membre
TommyDDR
Modérateur
Modérateur
Messages : 2086
Enregistré le : mar. 22 juil. 2008 21:55
Localisation : Nantes
Status : Hors ligne

Re: Règle des signes

#5

Message par TommyDDR »

Bien joué Mikell ! J'oublie tout le temps que StringReplace range le nombre de remplacement dans @extended :p

Voilà la version prenant en compte les chiffres (grossomodo, on découpe la chaine en plus de +/- consécutif et on appelle la fonction précédente pour chaque bloc).
Global $in = "++-+3---5++(2*-+3)+-1"
Signe($in)
ConsoleWrite($in & @crlf)

Func Signe(byref $in)
   Local $mode = (StringLeft($in, 1) == "+" Or StringLeft($in, 1) == "-")
   Local $retour = ""
   Local $concatPlusMoins = ""
   For $i = 1 To StringLen($in)
      Local $char = StringMid($in, $i, 1)
      Local $newMode = ($char == "+" Or $char == "-")
      If($newMode <> $mode) Then
         If($mode) Then
            $retour &= ReductionPlusMoins($concatPlusMoins)
            $concatPlusMoins = ""
         EndIf
         $mode = $newMode
      EndIf
      If($mode) Then
         $concatPlusMoins &= $char
      Else
         $retour &= $char
      EndIf
   Next
   $in = $retour
EndFunc

Func ReductionPlusMoins($in)
   Local $temp = StringReplace($in, "-", "")
   Return Mod(@extended, 2) == 0 ? "+" : "-"
EndFunc
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
mdanielm
Membre émérite
Membre émérite
Messages : 254
Enregistré le : mer. 11 déc. 2013 19:48
Status : Hors ligne

Re: Règle des signes

#6

Message par mdanielm »

Ta solution est bonne mais n'est pas plus simple que la mienne et surtout beaucoup plus lente.
Je rêvais d'une regex et d'une seule passe dans le texte.
Avatar du membre
TommyDDR
Modérateur
Modérateur
Messages : 2086
Enregistré le : mar. 22 juil. 2008 21:55
Localisation : Nantes
Status : Hors ligne

Re: Règle des signes

#7

Message par TommyDDR »

Attendez la réponse de mikell, si c'est faisable en regex, il vous pondra la solution telle une poule pond naturellement son oeuf :P
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
mdanielm
Membre émérite
Membre émérite
Messages : 254
Enregistré le : mer. 11 déc. 2013 19:48
Status : Hors ligne

Re: Règle des signes

#8

Message par mdanielm »

Une autre solution:
func Signe3(byref $in)
   $in = StringRegExpReplace($in, "([\+-]+)", "|$1|")
   Local $arr=Stringsplit($in,'|')
   $in=""
   for $i=1 to $arr[0]
      if StringRegExp($arr[$i], "^\+|-", 0) then
         $arr[$i] = StringReplace($arr[$i], '-', '')
         $in &= mod(@extended,2)=0 ? '+' : '-'
      Else
         $in &= $arr[$i]
      EndIf
   Next
EndFunc
Avatar du membre
jchd
AutoIt MVPs (MVP)
AutoIt MVPs (MVP)
Messages : 2272
Enregistré le : lun. 30 mars 2009 22:57
Localisation : Sud-Ouest de la France (43.622788,-1.260864)
Status : Hors ligne

Re: Règle des signes

#9

Message par jchd »

En plus concis :

Code : Tout sélectionner

Local $in = "++-+3---5++(2*-+3)+-1-++-+---+-++-+-+4"
Signe($in)
ConsoleWrite($in & @LF)

Func Signe(ByRef $in)
	$in = Execute("'" & StringRegExpReplace($in, "([+-]+)", "' & (Mod(StringLen(StringReplace('$1', '+', '')), 2) ? '-' : '+') & '") & "'")
EndFunc
Pour la ponte, j'imagine Mikell poursuivi par un coq en rut :lol:
La cryptographie d'aujourd'hui c'est le taquin plus l'électricité.
mdanielm
Membre émérite
Membre émérite
Messages : 254
Enregistré le : mer. 11 déc. 2013 19:48
Status : Hors ligne

Re: Règle des signes

#10

Message par mdanielm »

Je ne connaissais pas la méthode pour appliquer une fonction à $1.
On peut l'utiliser par exemple pour vérifier la présence d'une majuscule au début des phrases, et corriger éventuellement. A moins qu'il y ait plus simple?
Avatar du membre
Tlem
Site Admin
Site Admin
Messages : 11773
Enregistré le : ven. 20 juil. 2007 21:00
Localisation : Bordeaux
Status : Hors ligne

Re: Règle des signes

#11

Message par Tlem »

Bonsoir.
Moi j'aurais proposé ceci :

Code : Tout sélectionner

Func Signe4(ByRef $in)
	$in = StringReplace($in, "++", "+")
	$in = StringReplace($in, "--", "+")
	$in = StringReplace($in, "--", "+")
	$in = StringReplace($in, "+-", "-")
	$in = StringReplace($in, "-+", "-")
EndFunc
Qui est plus rapide et plus compréhensible qu'une expression régulière, malheureusement ce code ne fonctionne pas avec la chaine proposée par jchd. :cry:
Par contre ça fonctionne très bien avec la chaine proposée par mdanielm. :mrgreen: :P
Thierry

Rechercher sur le forum ----- Les règles du forum
Le "ça ne marche pas" est une conséquence commune découlant de beaucoup trop de raisons potentielles ...

Une idée ne peut pas appartenir à quelqu'un. (Albert Jacquard) tiré du documentaire "Copié n'est pas volé".
Avatar du membre
jchd
AutoIt MVPs (MVP)
AutoIt MVPs (MVP)
Messages : 2272
Enregistré le : lun. 30 mars 2009 22:57
Localisation : Sud-Ouest de la France (43.622788,-1.260864)
Status : Hors ligne

Re: Règle des signes

#12

Message par jchd »

C'est parce qu'un simple StringReplace, comme une expression régulière, ne marche "qu'en avant", c'est-à-dire qu'il ne revient pas sur ce qu'il vient de remplacer. La récursion dans PCRE ne concerne que des éléments de pattern, pas l'emplacement en cours dans le sujet.

Si on fait ça :

Code : Tout sélectionner

StringReplace("ZaaabaabaaabbW", "aab", "")
il se passe, en séquence (souligné = déjà été traité, gras = en cours de traitement) :
ZaaabaabaaabbW
ZaaabaaabbW
ZaaabaaabbW
ZaaaabbW
ZaaaabbW
ZaabW
ZaabW
Donc si l'entrée contient un nombre non borné de sous-chaînes à remplacer qui produiront d'autres sous-chaînes sujettes à remplacement, comme ci-dessus, il faudrait autant (donc un nombre non borné !) de StringReplace pour être certain d'effectuer tous les remplacements dans le cas général. Du coup c'est soit la récursion sur l'ensemble de la chaîne en cours de traitement, soit l'astuce à la Mikell qui fonctionne dans notre cas très particulier.

Que ce soit avec récursion ou dé-récursion (suite de remplacements explicites, en nombre forcément limité) il y a une limite au-delà de laquelle ça ne fonctionne plus (explosion de la pile ou dépassement du nombre maximum préu de remplacements) et ça a été la source d'innombrables bugs et "exploits" malveillants dans d'innombrables logiciels.

Seule une boucle non bornée (do .. until ou while 1 .. wend) apporte l'assurance de résultat correct dans tous les cas, ... sauf si l'entrée est un flux lui-même non borné, auquel cas on ouvre la voie à une paralysie partielle (DoS = denial of service) si on ne met pas un stéthoscope pour arrêter les frais.
La cryptographie d'aujourd'hui c'est le taquin plus l'électricité.
Avatar du membre
Tlem
Site Admin
Site Admin
Messages : 11773
Enregistré le : ven. 20 juil. 2007 21:00
Localisation : Bordeaux
Status : Hors ligne

Re: Règle des signes

#13

Message par Tlem »

Merci JC.
En fait, avant d'écrire mon message, j'en était arrivé à ceci :

Code : Tout sélectionner

Func Signe4(ByRef $in)
	Local $StrLen
	While 1
		$in = StringReplace($in, "++", "+")
		$in = StringReplace($in, "--", "+")
		$in = StringReplace($in, "--", "+")
		$in = StringReplace($in, "+-", "-")
		$in = StringReplace($in, "-+", "-")	
		If $StrLen = StringLen($in) Then ExitLoop
		$StrLen = StringLen($in)
	WEnd
EndFunc   ;==>Signe4
Mais non seulement ce n'est pas un code plus court, mais en plus ce code met deux fois plus de temps par rapport à la fonction Signe1.

Après, avec la fonction Signe1 (qui est la plus rapide de toutes) et pour grappiller quelques milliseconde :oops: , on peux aussi faire ça :

Code : Tout sélectionner

Func Signe5(ByRef $in)
	Local $StrLen
	While 1
		$in = StringRegExpReplace($in, "\+-|-\+", "-")
		$in = StringRegExpReplace($in, "\+\+|--", "+")
		If $StrLen = StringLen($in) Then ExitLoop
		$StrLen = StringLen($in)
	WEnd
	Return $in
EndFunc   ;==>Signe5
Sur une boucle de 100000 traitements, on arrive à gagner 2 à 4 secondes, mais bon ...
Thierry

Rechercher sur le forum ----- Les règles du forum
Le "ça ne marche pas" est une conséquence commune découlant de beaucoup trop de raisons potentielles ...

Une idée ne peut pas appartenir à quelqu'un. (Albert Jacquard) tiré du documentaire "Copié n'est pas volé".
Avatar du membre
jchd
AutoIt MVPs (MVP)
AutoIt MVPs (MVP)
Messages : 2272
Enregistré le : lun. 30 mars 2009 22:57
Localisation : Sud-Ouest de la France (43.622788,-1.260864)
Status : Hors ligne

Re: Règle des signes

#14

Message par jchd »

Je me suis conformé au cahier des charges :
Je recherche une regex, une seule, qui en une passe seulement remplace des séries de signes +, -, par un seul signe, en respectant la règle des signes
La cryptographie d'aujourd'hui c'est le taquin plus l'électricité.
Avatar du membre
jchd
AutoIt MVPs (MVP)
AutoIt MVPs (MVP)
Messages : 2272
Enregistré le : lun. 30 mars 2009 22:57
Localisation : Sud-Ouest de la France (43.622788,-1.260864)
Status : Hors ligne

Re: Règle des signes

#15

Message par jchd »

Je ne connaissais pas la méthode pour appliquer une fonction à $1.
On peut l'utiliser par exemple pour vérifier la présence d'une majuscule au début des phrases, et corriger éventuellement. A moins qu'il y ait plus simple?
C'est un brin délicat à claviotter au début, à cause de l'imbrication des quotes. Mais on peut l'employer pour faire de l'interception (enfin presque) par du code natif, un peu comme Perl le permet. Il y a des limitations car c'est seulement à la fin de la partie regexp, quand tout est joué, qu'on peut appliquer le code voulu au(x) groupe(s), capturés ou pas, dans la partie "replace". Alors que Perl permet d'appliquer du code natif à tout moment pendant la regexp.

J'aimerais beaucoup avoir le temps de déployer une UDF complète pour wrapper les APIs de PCRE2, mais c'est un bien trop gros morceau pour le peu de temps libre dont je dispose.
La cryptographie d'aujourd'hui c'est le taquin plus l'électricité.
Avatar du membre
mikell
Spammer !
Spammer !
Messages : 6292
Enregistré le : dim. 29 mai 2011 17:32
Localisation : Deep Cévennes
Status : Hors ligne

Re: Règle des signes

#16

Message par mikell »

jchd a écrit : mar. 19 mai 2020 22:11Pour la ponte, j'imagine Mikell poursuivi par un coq en rut :lol:
C'est absolument hors de question

ohh.jpg
ohh.jpg (5.72 Kio) Vu 10726 fois

Sinon, juste une petite UDF - même sommaire - pour faciliter l'emploi du SRER dans un Execute, ça serait super Image
J'ai toujours eu du mal avec ces fichues quotes
" L'échec est le fondement de la réussite. " (Lao-Tseu )
" Plus ça rate, plus on a de chances que ça marche " (les Shadoks )
Avatar du membre
jchd
AutoIt MVPs (MVP)
AutoIt MVPs (MVP)
Messages : 2272
Enregistré le : lun. 30 mars 2009 22:57
Localisation : Sud-Ouest de la France (43.622788,-1.260864)
Status : Hors ligne

Re: Règle des signes

#17

Message par jchd »

Quelque chose comme ça ?

Code : Tout sélectionner

Local $s = "++-+3---5++(2*-+3)+-1-++-+---+-++-+-+4"
Local $in = $s
Signe($in)
ConsoleWrite($in & @LF)

Local $sToDo = "(Mod(StringLen(StringReplace('$1', '+', '')), 2) ? '-' : '+')"
_RegExpReplacePostProc($s, "([+-]+)", $sToDo)
MsgBox(0, "", $s)

Func Signe(ByRef $s)
	$s = Execute("'" & StringRegExpReplace($s, "([+-]+)", "' & (Mod(StringLen(StringReplace('$1', '+', '')), 2) ? '-' : '+') & '") & "'")
EndFunc

Func _RegExpReplacePostProc(ByRef $sSubject, $sPattern, $sCode)
	$sSubject = Execute("'" & StringRegExpReplace($sSubject, $sPattern, "' & " & $sCode & " & '") & "'")
EndFunc
Bon, c'est brut de cul de poule (mpff !) mais ça marche.

On peut aussi prévoir de passer une array de codes différents (toujours en string) à appliquer à $1, $2, $3, ... mais le problème est alors de ficeler ensemble toutes les parties et plus il y en a plus ça devient tortueux.
Faut oublier, c'est ingérable !
La cryptographie d'aujourd'hui c'est le taquin plus l'électricité.
Avatar du membre
mikell
Spammer !
Spammer !
Messages : 6292
Enregistré le : dim. 29 mai 2011 17:32
Localisation : Deep Cévennes
Status : Hors ligne

Re: Règle des signes

#18

Message par mikell »

Oui quelque chose comme ça...
Avec une backreference c'est déjà bien
Je vais essayer de trafiquer ta fonction pour qu'elle affiche l'instruction finale avant son exécution
Image
" L'échec est le fondement de la réussite. " (Lao-Tseu )
" Plus ça rate, plus on a de chances que ça marche " (les Shadoks )
Avatar du membre
jchd
AutoIt MVPs (MVP)
AutoIt MVPs (MVP)
Messages : 2272
Enregistré le : lun. 30 mars 2009 22:57
Localisation : Sud-Ouest de la France (43.622788,-1.260864)
Status : Hors ligne

Re: Règle des signes

#19

Message par jchd »

J'ai regardé vite fait : 90% des utilisations que j'en ai eu (pour moi ou pour répondre à des demandes) il n'y avait qu'un groupe ($1) et le reste, quand on a besoin de $1, $2, $3 ... on peut tout grouper dans une seule expression/fonction.

Donc je dirais qu'en cas de besoin plus sophistiqué, on cpature tout ce qu'il faut et on traite les morceaux avec le code ad hoc.
La cryptographie d'aujourd'hui c'est le taquin plus l'électricité.
Avatar du membre
mikell
Spammer !
Spammer !
Messages : 6292
Enregistré le : dim. 29 mai 2011 17:32
Localisation : Deep Cévennes
Status : Hors ligne

Re: Règle des signes

#20

Message par mikell »

Très pratique en tout cas pour mon petit blocage avec les quotes...
Du coup je me suis fait la petite gui qui va bien :mrgreen: c'est pas infaillible mais ça va rudement me simplifier la vie
Purée comment j'y ai pas pensé avant ? :roll:

$gui = GuiCreate("constructeur Execute SRER", 950, 110, -1, 100)
GUISetFont(12, 400, 0, "Times New Roman", $gui, 5)
GuiCtrlCreateLabel("pattern", 20, 8, 100, 20)
GuiCtrlCreateLabel("remplacement (utiliser simples quotes)", 390, 8, 300, 20)
$input1 = GuiCtrlCreateInput("", 10, 30, 360, 25)
$input2 = GuiCtrlCreateInput("", 380, 30, 500, 25)
$btn = GuiCtrlCreateButton("go", 890, 30, 50, 25)
$input3 = GuiCtrlCreateInput("", 10, 70, 930, 25)
GuiSetState()

While 1
  $msg = GuiGetMsg()
  If $msg = -3 Then Exit
  If $msg = $btn Then
   $tomatch = GuiCtrlRead($input1)
   $todo = GuiCtrlRead($input2)
   $instr = 'Execute("''" & StringRegExpReplace($s, "' & $tomatch & '", "'' & ' & $todo & ' & ''") & "''")'
   GuiCtrlSetData($input3, $instr)
  EndIf
Wend
" L'échec est le fondement de la réussite. " (Lao-Tseu )
" Plus ça rate, plus on a de chances que ça marche " (les Shadoks )
Répondre