Reverse format string and determinate correct result

Viewed 59

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

3 Answers

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);
}

Using Regex.Match the function ExtractFieldAndDeterminateType can be written as:

public static string ExtractFieldAndDeterminateType(string input, out Type type)
{
    var extractedField = "";
    string required = "The (.*) field is (.*).";
    //string date = "The (.*) field is not a (.*)."; => Not needed
    string range = "(.*)(?= should be between)";
    type = Type.Unknown;

    var match = Regex.Match(input, required);
    if (match.Success)
    {
        extractedField = match.Groups[1].Value;
        switch (match.Groups[2].Value)
        {
            case "required":
                type = Type.Error;
                break;
            case "not a valid date":
                type = Type.Date;
                break;
        }
    }
    else if ((match = Regex.Match(input, range)).Success)
    {
        extractedField = match.Groups[1].Value;
        type = Type.Range;
    }
    else
    {
        //Nothing 
    }
    return extractedField;
}

Output on test data of OP:

Field is: Email and Type is: Error
Field is: Username and Type is: Error
Field is: InsertDate and Type is: Date
Field is: Age and Type is: Range

Edited: Added sample code to fiddle Link to fiddle

Try following :

    class Program
    {
        static void Main(string[] args)
        {
            string[] inputs = {
                                  "The Email field is required.",
                                  "The Username field is required.",
                                  "The InsertDate field is not a valid date.",
                                  "Age should be between 1 and 99."
                              };
            Type type;
            foreach (string input in inputs)
            {
                string word = ExtractFieldAndDeterminateType(input, out type);
                Console.WriteLine(word);
            }
            Console.ReadLine();
        }
        public static string ExtractFieldAndDeterminateType(string input, out Type type)
        {
            string[] words = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            int index = 0;
            if (words[0] == "The") index = 1;

            string word = words[index];

            switch (word)
            {
                case "Email" :
                    type = typeof(string);
                    break;

                case "Username":
                    type = typeof(string);
                    break;

                case "InsertDate":
                    type = typeof(DateTime);
                    break;

                case "Age":
                    type = typeof(int);
                    break;

                default:
                    type = (Type)Type.Missing;
                    break;
            }

            return word;
        }
    }
Related