Search code examples
c#formattingreverseformat-string

Reverse format string and determinate correct result


I have to reverse format string to extract "Email" and determinate the correct boolean result.

string input = "The Email field is required.";

string required = "The {0} field is required.";
string date = "The {0} field is not a valid date.";

bool isRequired = false;
bool isDate = false;

string extractedField;

My expectation is to get the value "Email" to "extractedField" and "isRequired" to true

UPDATE: Sorry if I was too general in explaining myself. To better clarify my intent I created a fiddle https://dotnetfiddle.net/cjPAo1


Solution

  • I believe i understood your query.You want to check which "expression" the current message matches, and depending on it, set the appropriate flag to true. Also retrieve the 'field' in question.

    One way to achieve it would be

    Update

    Based on your commented, has updated the code to support multiple fields.

    string input = "Age should be between 1 and 99.";
    string required = "The {0} field is required.";
    string date = "The {0} field is not a valid date.";
    string range = "{0} should be between {1} and {2}.";
    
    bool isRequired = false;
    bool isDate = false;
    bool isRange = false;
    string extractedField;
    
    
    var possibilities = new []
                        {
                            new KeyValuePair<string,Action>(ToRegex(required), ()=>((Action)(() => { isRequired = true;}))()),
                            new KeyValuePair<string,Action>(ToRegex(date), ()=>((Action)(() => { isDate = true;}))()),
                            new KeyValuePair<string,Action>(ToRegex(range), ()=>((Action)(() => { isRange = true;}))())
                        };
    var result = possibilities
                 .Where(x=>Regex.Match(input,x.Key).Success)
                 .Select(x=> new KeyValuePair<IEnumerable<string>,Action>( 
                                                Regex.Match(input,x.Key).Groups.Cast<Group>().Where(c=>c.Name.StartsWith("Field")).Select(c=>c.Value),
                                                x.Value)).First();
    
    
    var fields = result.Key;
    result.Value();
    Console.WriteLine($"{nameof(extractedField)}={string.Join(",",fields)},{Environment.NewLine}{nameof(isRequired)}={isRequired},{Environment.NewLine}{nameof(isDate)}={isDate}");
    

    Where ToRegex is defined as

    public string ToRegex(string value)
    {
        var result = new List<string>();
        foreach(var item in value.Split(' '))
        {
            if(Regex.Match(item,@"{(?<Value>\d*)}").Success)
            {
                var match = Regex.Match(item,@"{(?<Value>\d*)}");
    
                result.Add(Regex.Replace(item,@"{(?<Value>\d*)}",$"(?<Field{match.Groups["Value"].Value}>\\S*)"));
                continue;
            }
            result.Add(item);
        };
        return string.Join(" ",result);
    }
    

    Demo Code

    The above code uses Regex to find the appropriate match.

    Sample Output

    extractedField=Age,1,99,
    isRequired=False,
    isDate=False
    

    Update

    Based on your comment, to support multiple words, you could use the following.

    public string ToRegex(string value)
    {
        var result = new List<string>();
        foreach(var item in value.Split(' '))
        {
            if(Regex.Match(item,@"{(?<Value>\d*)}").Success)
            {
                var match = Regex.Match(item,@"{(?<Value>\d*)}");
    
                result.Add(Regex.Replace(item,@"{(?<Value>\d*)}",$"(?<Field{match.Groups["Value"].Value}>[\\S ]*)"));
                continue;
            }
            result.Add(item);
        };
        return string.Join(" ",result);
    }