tags:

views:

43

answers:

3

This sounds simple but my regex knowledge is limited.

I need an expression to match a decimal number or the string "all", as in a range validator that allows the word all represent the max range.

I thought something like this might work:

((^[-+]?\d*\.?\d*)|any)

But the above doesn't work for "any".

+1  A: 

try this

(((-|\+)?\d+\.?\d*)|any)
Sky Sanders
Awesome! This seems to work fine.Thank you.
HectorMac
@Sky: `(?:…)` is just grouping. Look-around is `(?=…)` and `(?!…)`.
KennyTM
@Kenny, thanks for correcting me. I am a little loose today.
Sky Sanders
+1  A: 

With | the regex engine will likely check each possibility one by one, and return immediately if a match is found.

Since the subexpression

(^[-+]?\d*\.?\d*)

matches an empty string, the LHS of | will always succeed, thus the any part will always be ignored.

You should make this part not match an empty string, e.g.

(^[-+]?(?:\d+\.?\d*|\.\d+))
KennyTM
@Sky: But the original regex has `[-+]?` so the sign is optional. Did I miss something?
KennyTM
@KennyTM - right you are - RX dyslexia on my part - i read the caret inside the class brackets
Sky Sanders
+2  A: 

Here is a solution that does not make use of regex.

private static bool IsNumberOrGivenString(string number, string text, CultureInfo culture)
{
    double result;
    if (double.TryParse(number, NumberStyles.Float, culture, out result))
    {
        return true;
    }

    return number.Equals(text, StringComparison.OrdinalIgnoreCase);
}

private static bool IsNumberOrGivenString(string number, string text)
{
    return IsNumberOrGivenString(number, text, CultureInfo.InvariantCulture);
}

Sample use:

Console.WriteLine(IsNumberOrGivenString("898", "all")); // true
Console.WriteLine(IsNumberOrGivenString("all", "all")); // true
Console.WriteLine(IsNumberOrGivenString("whatever", "all")); // false
Console.WriteLine(IsNumberOrGivenString("898,0", "all", CultureInfo.GetCultureInfo("sv-SE"))); // true
Console.WriteLine(IsNumberOrGivenString("898,0", "all", CultureInfo.GetCultureInfo("en-US"))); // false

The upsides with this code over using a regex is that it (may) run in a localized manner, using whatever decimal sign that is used. It will also fail the number if it has, say a . in it, when that character is not a valid decimal separator.

Since the string comparison is ignoring case it will also match the word "all" regardless of whether it is "all", "All", "aLl" or any other combination of upper- and lowercase letters.

Fredrik Mörk
Not sure how this solves the OP problem, Fredrik. You are in a chicken/egg situation. Where does the string that feeds your function come from?
Sky Sanders
@Sky: the string needs to be somewhere, right? Either it's in the regex pattern, hard coded into the function, or passed as a parameter. My code sample simply suggests a flexible way of solving it. If it would be better to hard-code it, read it from a config file or fetch it from somewhere else, that can be easily done. By not coding the string into the method itself, it becomes more reusable.
Fredrik Mörk
@Fredrik - I think you missed my point: The OP is trying to parse a decimal value or a string constant from some indeterminant source. How is he to supply, from this indeterminant source, a value that is parsable by your function? A regex? ;-) and don't read this as a bag on you. I already upvoted you. It just seems that this does not solve the problem as given. And I am not implying that you assert otherwise.
Sky Sanders
@Sky: then I think I reather missed the OP's point. I understood it as the regex should match any number or the text "all" (alternatively the text "any", depending on if you read the title or the question). Now I understand what you mean with your comments. Still not sure how to interpret the question though. Either way, I'll leave the answer as it is for now.
Fredrik Mörk