4

I am receiving an input string that is a Regex pattern that I need to randomly generate a string matching that pattern. I did not know if this entailed parsing through the regex string piece by piece and using a random generator for each part, or if there was a class that has this functionality out of the box.

Example:

Input string = "[0-9][A-Z]"

Possible outputs = "1A", "9B", etc..

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
Pipeline
  • 1,029
  • 1
  • 17
  • 45

2 Answers2

3

From what I could find, Xeger is the most popular solution, but it is in Java..

However, apparently there is a C# version: Fare.
If you read the description, they say that Xeger was partially ported into Fare application, but not fully.

Included a .NET port of Xeger, for generating random text from regular expressions. Xeger does not support all valid Java regular expressions. The full set of what is defined here and is summarized at (http://code.google.com/p/xeger/wiki/XegerLimitations).

I have not tested it and don't know if/how it works, though. So use at your own discretion. i couldn't find anything else that is easy and ready to go, which seems like a gap. You'd think that there would be some pre-made class...

If you know that you need this for something relatively simple, then I'd say you are better off writing your own small RegexGenerator. It does entail you parsing each piece of input "[..]" and using Random in order to generate that piece of the string.

Roman
  • 1,727
  • 1
  • 20
  • 28
  • var xeger = new Xeger(value); var result = Regex.IsMatch(xeger.Generate(), value); How does this exactly work? result is a boolean I am not sure where the newly generated string now lives in xeger? – Pipeline Jul 30 '15 at 19:19
  • @Pipeline: xeger.Generate() generates the random string. Checking it back against the pattern (`value`) makes it a simple Unit Test. – Thomas Weller Jul 30 '15 at 20:04
2

If you can control the input why not write one? I have taken your two examples and added \d as an option as well. You will have to work out all combinations which only you know the user will provide.


User Input

Say the user has:

var input = "[0-9][A-Z]";

That is two replacement placeholder characters, one for a number and an uppercase letter.

Placeholder

So let us create a placeholder class responsible for holding each of the items, but it is also responsible for generating a random character. Here is the designed class

public class PlaceHolder
{
    public Random RND { get; set; } // Supplied random number generator

    public string Pattern { get; set; } // User Pattern
    public string Characters { get; set; } // Characters available to use
    public string ReplaceChar              // Generated random character based on pattern.
    {
        get { return Characters[RND.Next( Characters.Length )].ToString(); }
    }
}

Placeholder Mappings

So we setup the placeholder possibilities of the generator as such:

Random rn = new Random();
var PlaceHolders = new List<PlaceHolder>()
{
 new PlaceHolder() { Pattern = "[A-Z]", Characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",  RND=rn },
 new PlaceHolder() { Pattern = "[0-9]", Characters = "0123456789", RND=rn  },
 new PlaceHolder() { Pattern =  @"\d",  Characters = "0123456789", RND=rn  }
};

Parse

Now we will have to parse the user input to determine what random text is needed per the user's input.

Before we can do that we need to create a regex pattern based on all the placeholders we have. So let us generate that pattern based off of them but escape the regex special characters and place the placeholders in match parenthesis ( ) so we can match them.

// Create pattern such as `[A-Z]|[0-9]|\d` but it escapes the regex specials
// to return `(\[A-Z])|(\[0-9])|(\\d)`
var pattern = 
      string.Join("|", PlaceHolders.Select (ph => Regex.Escape(ph.Pattern))
                                   .Select (pttrn => string.Format("({0})", pttrn)));

Generate Result

Now we parse the input, and project the matches found to the Placehoders. Once we have the correct placeholders we generate the random text against it.

string.Join(string.Empty, 
            Regex.Matches(input, pattern)
                 .OfType<Match>()
                 .Select (mt => PlaceHolders.Find(ph => ph.Pattern == mt.Groups[0].Value) )
                 .Select (plc => plc.ReplaceChar))

Actual Results

 1X
 0B
 ...

This is loosely based off my blog article C#: Generate a Random Sequence of Numbers and Letters From a User Defined Pattern and Characters « OmegaMan's Musings which I will have to update with this scenario.

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122