[RegEx] Remplacer la même occurrence

Bonjour bon jour messieurs-dames.
Si je vous écris de ce bon midi, c’est pour vous exposer un problèmes qui me taraude trop pour mon simple esprit.
N’étant pas très doué, c’est après avoir perdu ma matinée que je viens ici parmi vous, mes frères, pour vous exposer mon problème d’expressions régulières.

Voici le bout d’un script

SELECT id_Toto as nbToto, sz_Toto as txtToto FROM Table
Je cherche à faire un replace pour remplacer “Toto” par “Titi” avec des petites fleurs à gauches à droite :

SELECT --> Modification id_Titi as nbTiti, --< Fin Modification --> Modification sz_Titi as txtTiti --< Fin Modification From Table

Alors voici l’expression régulières que j’ai sous la main et sa valeur de remplacement :

codeToto(?.*$)
${space}–> Modification\r\n${debut}Titi${fin}${space}–< Fin Modification[/code]
(le ${space} c’est pour garder les tabulations dans le script)

Cela fonctionne presque bien, et de fait, voici ma question, enfin.
Lorsque j’exécute le replacement, la moitié est pris en main
ou plus exactement, voilà ce que j’obtiens :

SELECT --> Modification id_Toto as nbTiti, --< Fin Modification --> Modification sz_Toto as txtTiti --< Fin Modification From Table

Logiquement, et parce que je suis fénéant, il suffit de l’exécuter à nouveau, pour obtenir le script qu’il me faut :

SELECT --> Modification --> Modification id_Titi as nbTiti, --< Fin Modification --< Fin Modification --> Modification --> Modification sz_Titi as txtTiti --< Fin Modification --< Fin Modification From Table
Or on en voit l’inconvénient, je ne veux pas du doublon. Je trouve cela génant.

Après maintes tentatives, je ne suis capable que de deux réussites :
1 - J’arrive à remplacer tous les “Toto” mais sans les commentaires “Modification” (donc sans prise en compte du début et fin de ligne)
2 - J’ai ce qu’il faut, mais une occurrence à la fois par ligne.

Avant donc que mon pauvre cerveau ne cède, j’en viens donc à prier votre aide, qu’une bonne âme puisse me sauver, de ce bourbier dans lequelle je me suis fourré.

Merci

PS: Stop drugs

Il doit manquer un truc comme “g” par exemple qui dit qu’il faut appliquer l’expression régulière à toute la phrase plutôt que de s’arrêter à la première.
Ça varie en fonction des langages, mais ya de fortes chances que ça soit ça.

Oui, en perl c’est tranquille emile avec les modificateurs /gm :slight_smile: sinon c’est quoi le langage utilisé ?

C’est en C#, mais je fais mes tests avec une petite appli (The Regulator).
J’essaie de trouver la définition de /g et son équivalent en C#

[quote=“Xas, post:4, topic: 48351”]C’est en C#, mais je fais mes tests avec une petite appli (The Regulator).
J’essaie de trouver la définition de /g et son équivalent en C#[/quote]

g c’est greedy (avide) et m c’est multiline (!). En meme temps, il doit bien y avoir un dieu vivant du C# qui traine par ici.

Google said:

(Source)

J’ai compris l’option /g, malheuresement cela ne répond pas à mon problème.
Remplacer plusieurs fois la même occurrence dans une même ligne, ça, j’ai pas de problème.
Ce que j’essaie de faire, et qui semble impossible c’est de modifier toutes les occurrences de la ligne et d’ajouter un texte avant la ligne et après la ligne.
Pour l’instant je n’arrive qu’à remplacer une seule occurrence à la fois.
Je pense que je vais finir par devoir utiliser la méthode Replace avec l’option delegate…

T’as essayé “mon” bout de code?

Oui, oui, j’étais déjà en multiline

Faire ce que tu veux faire en un seul Regex ca me semble pas possible. Je le ferais en deux coups:

_ un Regex.Replace avec:
–> (?^(?\s*).?Toto)(?.?$) en pattern
–> ${space}–> Modification\r\n${debut}${fin}${space}\r\n–< Fin Modification en remplacement

pour avoir Modification / Fin Modification là où il y aura modification et ensuite
_ un Regex.Replace(“Toto”, “Titi”)

Je le ferais sans multiline par contre.

[code]using System;
using System.Text;
using System.Text.RegularExpressions;

namespace XasSuceDesOurs
{
class Program
{
public static Regex regex = new Regex(
« (?^(?:(?:(?.?)(?Toto)(?.?))+)$) »,
RegexOptions.IgnoreCase
| RegexOptions.Multiline
| RegexOptions.CultureInvariant
| RegexOptions.Compiled
);

	static void Main(string[] args)
	{
		string text = "SELECT\r\nid_Toto as nbToto\r\nsz_Toto as txtToto\r\nFROM Table";
		MatchCollection mc = regex.Matches(text);
		foreach (Match m in mc)
		{
			if (m.Success)
			{
				text = regex.Replace(text, new MatchEvaluator(toto));					
			}
		}

		Console.Write(text);
		Console.WriteLine();
	}

	static string toto(Match m)
	{
		if (!m.Groups["toto"].Success && m.Groups["toto"].Captures.Count <= 0) return m.ToString();

		string result = string.Format("--> Modification{0}{1}{0}--< Modification", Environment.NewLine, m.ToString());
		result = result.Replace("Toto", "Titi");

		return result;
	}
}

}[/code]

Résultat :

SELECT --> Modification id_Titi as nbTiti --< Modification --> Modification sz_Titi as txtTiti --< Modification FROM Table Appuyez sur une touche pour continuer...

Edit: bon, note bien que tu peut alléger la regex, là c’est juste pour la lisibité. Maintenant j’ai juste tester avec ton exemple, je sais pas si ca va marcher pour tous les cas que tu peut rencontrer (genre si t’a du ORDER BY ou des conneries comme ca). Mais maintenant que t’a les grandes lignes, tu devrais pouvoir gérer :slight_smile:

Alors tout d’abord merci à MadGnome.
C’était une solution à laquelle j’avais pensé, mais n’étant pas roi des expressions je pensais qu’on pouvait remplacer par “recursivité” un groupe d’occurrence d’une capture…

Du coup j’ai pris la solution .NET du delegate MatchEvaluator, avec la simple excuse d’apprendre une autre méthode.

Du coup, bishop, gros merci mon ours, j’ai fait comme toi, en un peu plus leger (plus violent ?) :

[code]strProcedure = rxTiti.Replace( strProcedure, new MatchEvaluator(EvaluateCompte) );

public static string EvaluateCompte( Match m )
{
StringBuilder stb = new StringBuilder( m.Groups[“space”].Value );
stb.Append( “–> Modification\r\n” );
stb.Append( m.Value.Replace( “Toto”, “Titi” ) );
stb.Append( m.Groups[“space”].Value );
stb.Append( “–< Fin Modification” );
return stb.ToString();
}[/code]
Et j’en profite pour lancer quelques questions sur ta solution qui m’interpelle à certains endroits dont je tairais le nom (coquin va !)

Pourquoi passes-tu par un regex.Matches ?
Quand j’ai vu ta solution je me suis dit : "ha merde, mon code va foutre les blocs “Modification” en début et fin de script, voire partout, et en fait non.
Donc je suppose que .NET s’occupe déjà d’appeller la méthode à chaque succès ?
Je pose la question d’un point de vue optimisation d’exécution, parce que ça m’intéresse.

[HS]tin mon salo, j’avais pas vu que t’étais enfin reviendu sur le net. J’attendais depuis le 8 janvier je crois…[/HS]

Passque j’ai pas fait gaffe et que j’ai pas nettoyé mon code, tout empressé de briller sur le forum en braillant du « Eureka ! ». On peut limiter Main() à :

[code] static void Main(string args)
{
string text = « SELECT\r\nid_Toto as nbToto\r\nsz_Toto as txtToto\r\nFROM Table »;

		text = regex.Replace(text, new MatchEvaluator(toto));

		Console.Write(text);
		Console.WriteLine();
	}[/code]

[quote=« Xas, post:12, topic: 48351 »]Quand j’ai vu ta solution je me suis dit : "ha merde, mon code va foutre les blocs « Modification » en début et fin de script, voire partout, et en fait non.
Donc je suppose que .NET s’occupe déjà d’appeller la méthode à chaque succès ?
Je pose la question d’un point de vue optimisation d’exécution, parce que ça m’intéresse.[/quote]
Yep. Match retourne juste la ligne concernée, et c# fait le remplacement de cette chaine là dans celle d’origine. Niveau optimisation, j’en ai pas la moindre idée.

Je suis revenu mollement :slight_smile: A mon age, je voudrais pas me faire un claquage de l’internet.