CkyRoomee
CkyRoomee

Reputation: 78

String validation based on a custom format

I want to validate a string based on custom format: (_.__,_.__). This should be a decimal input followed by a comma followed by another decimal input, wrapped in a parentheses—e.g.(1.01,3.21). I want the string pattern to accept one and more entries—e.g.(1.01,3.21)(3.01,4.51)...(2.1,5.6). Is it possible to do that?

Upvotes: 5

Views: 211

Answers (3)

user10216583
user10216583

Reputation:

One way to solve this is:

  • Use RegEx to return the matches of the (x,y) pattern.
  • Use the extension methods to extract the x and y.
  • Check whether the x and y are of decimal type using decimal.TryParse(..) method.
  • Check whether the input string contains something else other than the required pattern.
private bool IsValidInput(string input)
{
    var pattern = @"\((.*?)\s?,\s?(.*?)\)";
    var xpatt = @"\s+\(|\s+\)|\,\(|\)\,|\)\s+|\({2,}|\){2,}|^\)\(|\)\($";
    var q = Regex.Matches(input, pattern)
        .Cast<Match>()
        .SelectMany(x => x.Groups.Cast<Group>()
        .Skip(1))
        .Select(x => x.Value);

    return !Regex.IsMatch(input, xpatt)
        && q.Count() > 0 
        && input.Replace(" ","").Length 
        == (input.Count(x => x == '(' || x == ')' || x == ',') 
        + q.Sum(x => x.Length))
        && q.All(x => decimal.TryParse(x, out _));
}

So, the function returns:

(1.01, 3.21)(3.01, 4.51)(2.1, 5.6)     => true
(abc, 3.21)(3.01, 4.51)(2.1, 5.6)      => false
(3.21)(3.01, 4.51)(2.1, 5.6)           => false
1.01, 3.2 13.01, 4.51 2.1, 5.6         => false
1.01, 3.21)(3.01, 4.51)(2.1, 5.6)      => false
(1.01, 3.21)(3.01, 4.51)(2.1, 5.6      => false
1.01, 3.21)3.01, 4.51)2.1, 5.6)        => false
(1.01, 3.21)3.01, 4.51(2.1, 5.6)       => false
(1.01, 3.21)abc(3.01, 4.51)(2.1, 5.6)  => false
(1.01, 3.21)(3.01, 4.51)abc(2.1, 5.6)  => false
abc(1.01, 3.21)(3.01, 4.51)(2.1, 5.6)  => false
(1.01, 3.21)(3.01, 4.51)(2.1, 5.6)abc  => false

Upvotes: 3

Cray
Cray

Reputation: 2850

You can either use

(?:\(\d+(?:\.\d+)?,\d+(?:\.\d+)?\))+

or with global flag

\(\d+(?:\.\d+)?,\d+(?:\.\d+)?\)

First solution will match your pattern 1 or more times and returns a single match. The second will match your pattern only once. However with global flag you will get all matches as separate results.

Explanation:

(?:                   //begin non-capturing group
  \(                  //match opening parentheses
    \d+               //match 1 or more numbers
    (?:\.\d+)?        //optionally match a dot followed by 1 or more numbers
    ,                 //match a comma
    \d+(?:\.\d+)?     //same pattern as before comma
  \)                  //match closing parentheses
)+                    //close non-capturing group, match the group 1 or more times

Upvotes: 1

Snagtz
Snagtz

Reputation: 118

I think this should do the trick for your problem: ^(?:\(\d+(?:\.\d+)?,\d+(?:\.\d+)?\))+$ try it out Currently I made all capturing groups non capturing groups since I was not sure about any specific subgroups you wanted to capture.

Upvotes: 0

Related Questions