Home > Software engineering >  Regex to replace numbers in a string with numbered placeholders
Regex to replace numbers in a string with numbered placeholders

Time:12-04

I have a regex to replace numbers in a string with the value @p but I want to replace the same numbers with the same @p1 and then @p2 and @p3 and so on.

This is the sample string

23 44 56 83 23 83 103 6573 56

My current simple replacement would return this

@p @p @p @p @p @p @p @p @p

what I want is this

@p1 @p2 @p3 @p4 @p1 @p4 @p5 @p6 @p3

So the same number would return the same @p number .

My regex matching string is this @"\b[0123456789] \b"

so currently I do this

public static System.Text.RegularExpressions.Regex Reg_pass_numbers = new 
System.Text.RegularExpressions.Regex(@"\b[0123456789] \b");
StringHolder = Reg_pass_Hex.Replace(StringHolder, "@p");

StringHolder holds my input string .

Can regex help with this?

CodePudding user response:

Agree with Llama. A MatchEvaluator is a piece of code that specifies what value should be used for replacement during a Regex replace

var r = new Regex(@"\d ");
var i = "23 32 23";
var d = new Dictionary<string, int>();
var x = 1;
var o = r.Replace(
  i,
  new MatchEvaluator(m => d.TryGetValue(m.Value, out var v)? $"@p{v}" : $"p{d[m.Value]=x  }")
);
  

There's a bit to unpick in this so..

  • your Regex can be simplified to just "one or more digits".
  • we have a variable x that we increment every time we find a new match we never saw before
  • we have a dictionary that tracks matches we saw
  • the match evaluator code gets the matched value eg "23" in m.Value
  • we try get the dictionary value into v; if it succeeds we use v. If it doesn't we add a new dictionary entry for m.Value with the current value of x and then increment x

If you want to make some sql parameters out of this and want to know what values go with what parameters, enumerate the whole dictionary : the key value pair's Value is the p number and the Key is the value string

CodePudding user response:

You can use Regex.Replace, but when replacing you can check if match appeared earlier with help of dictionary:

// try adding a new match
dict.TryAdd(m.Value, dict.Count   1) 
  ? dict.Count    // succeed, just return its number
  : dict[m.Value] // failed to add, the match already exists, take its number

Code:

string source = "23 44 56 83 23 83 103 6573 56";

Dictionary<string, int> dict = new Dictionary<string, int>();

string result = Regex.Replace(
  source, 
 "[0-9] ", 
  m => $"@p{(dict.TryAdd(m.Value, dict.Count   1) ? dict.Count : dict[m.Value])}");
  • Related