0

I need help with creating regex for validating parameter string.

Parameter string consists of 2 optional groups of explicit characters. First group can contain only one occurrence of P, O, Z characters (order doesn't matter). Second group has same restrictions but can contain only characters t, c, p, m. If both groups are presented, they need to be delimited by a single space character.

So valid strings are:

P t
PO t
OZP ct
P tcmp
P
PZ
t
tp

etc.

Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
user2219927
  • 5
  • 1
  • 4
  • This is not really a good fit for a regex. Does it have to be one? Why? – Tim Pietzcker Mar 10 '14 at 14:05
  • user is calling service with optional filter parameter(flag). First group should filter data by main category, second group filter data by subcategories. Every category has assigned special character. I just want to be sure that paramter that user present is in right format so I can proceed request. – user2219927 Mar 10 '14 at 14:10
  • What would you like to do about duplicates, i.e. `PPP ttttt`, reject or allow? – Jodrell Mar 10 '14 at 14:23
  • @Jodrell: He wants to reject them ("can contain *only one occurrence* of..."). – Tim Pietzcker Mar 10 '14 at 14:26

3 Answers3

2

Why not ditch regex, and using string to represent non string data, and do

[Flags]
enum First
{
    None = 0,
    P = 1,
    O = 2,
    Z = 4
}

[Flags]
enum Second
{
    None = 0
    T = 1,
    C = 2,
    P = 4,
    M = 8
}

void YourMethod(First first, Second second)
{
    bool hasP = first.HasFlag(First.P);
    var hasT = second.HasFlag(Second.T);
}

You could then call YourMethod like this.

// equivalent to "PO mp", but checked at compile time.
YourMethod(First.P | First.O, Second.M | Second.P);

or, if you felt like it

// same as above.
YourMethod((First)3, (Second)12);

If you'd like to know more about how this works see this question.

Community
  • 1
  • 1
Jodrell
  • 34,946
  • 5
  • 87
  • 124
1

I don't think a regex is a good solution here, because it will have to be quite complicated:

Regex regexObj = new Regex(
    @"^               # Start of string
    (?:               # Start non-capturing group:
     ([POZ])          # Match and capture one of [POZ] in group 1
     (?![POZ]*\1)     # Assert that that character doesn't show up again
    )*                # Repeat any number of times (including zero)
    (?:               # Start another non-capturing group:
     (?<!^)           # Assert that we're not at the start of the string
     \                # Match a space
     (?!$)            # Assert that we're also not at the end of the string
    )?                # Make this group optional.
    (?<!              # Now assert that we're not right after...
     [POZ]            # one of [POZ] (i. e. make sure there's a space)
     (?!$)            # unless we're already at the end of the string.
    )                 # End of negative lookahead assertion
    (?:               # Start yet another non-capturing group:
     ([tcpm])         # Match and capture one of [tcpm] in group 2
     (?![tcpm]*\2)    # Assert that that character doesn't show up again
    )*                # Repeat any number of times (including zero)
    $                 # End of string", 
    RegexOptions.IgnorePatternWhitespace);
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • I'd like to vote this up but, can't get it to work here http://derekslager.com/blog/posts/2007/09/a-better-dotnet-regular-expression-tester.ashx – Jodrell Mar 10 '14 at 14:47
  • @Jodrell: Works for me - did you check `IgnorePatternWhitespace`? – Tim Pietzcker Mar 10 '14 at 14:51
  • works a treat if I test at Regex Hero with `IgnorePatternWhitespace` and `Multiline`. http://regexhero.net/tester/ – Jodrell Mar 10 '14 at 14:58
-1

This should give you what you need:

([POZ]+)? ?([tcpm]+)?
Kevin Blake
  • 434
  • 2
  • 5