简体   繁体   中英

How to pull a variable out of a string I need to compare to another, pre-existing string c#

I have a rules engine that takes a string as a name of a rule, and compares it to a string, predicate dictionary. I'm writing a rule that will compare two datetimes and return true if they match, but allow a windows of a configurable number of seconds. Ideally, I'd like for my string/predicate key value pair to look something like

{"Allow <x> seconds", AllowXSeconds}

A user applying the rule would decide they would like a 10 second window on either side of the original datetime so they would say "Allow 10 seconds" in config. I want my code to be able to to recognize that the user wants to apply the "Allow seconds" rule, then pull the "10" out so I can use it as a variable in the rule's logic. I'd rather not use regex, as the class is already built, and I don't know if I'll be allowed to refactor it in that way. I will, though, if no one has any clever ideas on how to do this. Thanks in advance, to all you smart guys and gals!

You can validate using string.StartsWith and string.EndsWith then use string.Substring to get the desired value and int.TryParse to attempt to parse the value and validate that it is an integer

string str = "Allow 10 seconds";
int result;
if (str.StartsWith("Allow ") 
    && str.EndsWith(" seconds") 
    && int.TryParse(str.Substring(6, str.Length - 14), out result))
{
    Console.WriteLine(result);
}
else
{
    Console.WriteLine("Invalid");
}

Also if desired there are overloads of StartsWith and EndsWith that will allow for case insensitive matching as well.

This looks like a perfect candidate for regular expressions.

Here is a LINQPad program that demonstrates:

void Main()
{
    var lines = new[]
    {
        "Allow 10 seconds",
        "Allow 5 seconds",
        "Use 5mb"
    };

    var rules = new Rule[]
    {
        new Rule(
            @"^Allow\s+(?<seconds>\d+)\s+seconds?$",
            ma => AllowSeconds(int.Parse(ma.Groups["seconds"].Value)))
    };

    foreach (var line in lines)
    {
        bool wasMatched = rules.Any(rule => rule.Visit(line));
        if (!wasMatched)
            Console.WriteLine($"not matched: {line}");
    }
}

public void AllowSeconds(int seconds)
{
    Console.WriteLine($"allow: {seconds} second(s)");
}

public class Rule
{
    public Rule(string pattern, Action<Match> action)
    {
        Pattern = pattern;
        Action = action;
    }

    public string Pattern { get; }
    public Action<Match> Action { get; }

    public bool Visit(string line)
    {
        var match = Regex.Match(line, Pattern);
        if (match.Success)
            Action(match);
        return match.Success;
    }
}

Output:

allow: 10 second(s)
allow: 5 second(s)
not matched: Use 5mb

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM