Henryk Budzinski
Henryk Budzinski

Reputation: 1293

DataAnnotation RegularExpression problems

Why RegularExpressionAttribute validation doesn't compare the input string with the value of all matches concatenated?

I asked a question here about the scenario below, but I found a solution the next day and found it better to raise the issue here.

[Required(
    AllowEmptyStrings = false,
    ErrorMessage = "Required")]
[RegularExpression(
    "^[^0]{1}|..+",
    ErrorMessage = "Expressao Regular")]
public string EncryptedValue { get; set; }

Except by empty string or "0", the property should be valid in ModelState, but:

enter image description here

You can test HERE the expression and value.

Expression
^[^0]{1}|..+

Value
+iCMEBYZQtWbnU2RPX/MmqrDPuVJzSGGWhkFd+9/zpMbHVoOlZFuF9ND1xAxsQy3YFCPIsUBEgg2RJNkPefrmQ==

You will notice that the expression match, but with two matches. The first match itself are not equals to the input string, you need to concatenate both match value to reach that.

But apparently this is not done in the validation of ModelState, even with jquery.validate.unobtrusive this happens (with jquery, I need to click in submit button two times to see this, but it's happens).

Solution
You need to build an expression that match input string completelly in the first match.

When you build a expression to validate a field, every OR in your expression must match all the input string.

So whenever you mount an expression with OR operators, always mount from largest input to smallest input.

In this case:
From ^[^0]{1}|..+ to ..+|^[^0]{1}

Upvotes: 0

Views: 715

Answers (2)

mayo
mayo

Reputation: 4075

So, if your regex is ^[^0]{1}|..+

And you value is : +iCMEBYZQt...

One match it will be +, and the other: iCMEBY0ZQt....

The thing is, in the first part ^[^0]{1}, your regex try to match any character that is not 0, once (at the beginning of the line/string). So, the regex looks the string and say something like:

Voilah!! I have something that is not zero, at the beginning and is one character, the character is : +, Thanks, thanks, where is my cookie?!

Also, the or instruction (|) tells the regex to be more flexible about the patterns and is something like, If you don't find the first expression, don't feel bad, you also can look for this another thing. But once the regex has the first cookie doesn't make sense to go back and try to look again for the second expression (..+) because already found a solution for the first expression, and the regex knows that there will not be extra cookies for the same work. So, life continues and we have to move on.

Here you can see that the first and the second expressions are independent ways to satisfy the regex.

Regex with Or

https://regex101.com/r/UWtcF8/3


Your second regex is : ..+|^[^0]{1}:

Second regex with Or

https://regex101.com/r/la3wDa/1

Where the order of the expressions are swapped. This is the same but the first expression that the regex will try to satisfy is ..+ which basically is give anything that involves 2 or more characters. So for example if you have 00, the regex will say:

Yumm, cookies !

And that can be fine or not, it will depend on what you want to solve.


Now another option is:

^(?!0$).+

Regex with negative lookahead

https://regex101.com/r/gxJdch/1

Where we are going to look for anything but a single zero.


Useful and fun links: https://regex101.com/ < Even when you are not working on php you can select the php version and check regex debugger to learn more things about regex!) https://regexper.com/

Upvotes: 0

Z.R.T.
Z.R.T.

Reputation: 1603

let's take a look at class System.ComponentModel.DataAnnotations.RegularExpressionAttribute . we are interested in the following method :

 [__DynamicallyInvokable]
public override bool IsValid(object value)
{
  this.SetupRegex();
  string input = Convert.ToString(value, (IFormatProvider) CultureInfo.CurrentCulture);
  if (string.IsNullOrEmpty(input))
    return true;
  Match match = this.Regex.Match(input);
  if (match.Success && match.Index == 0)
    return match.Length == input.Length;
  return false;
}

In our case we have regex expression "^[^0]{1}|..+" and input string +iCMEBYZQtWbnU2RPX/MmqrDPuVJzSGGWhkFd+9/zpMbHVoOlZFuF9ND1xAxsQy3YFCPIsUBEgg2RJNkPefrmQ== . Regex validation return two matches, the first + (first symbol) and the second is the rest part. the first match length less then input string, that is why IsValid return false.

Why RegularExpressionAttribute validation doesn't compare the input string with the value of all matches concatenated? because it works with the first match

Upvotes: 2

Related Questions