Regular expression in RegularExpressionAttribute behavior

Viewed 267

I am using this regular expression: @"[ \]\[;\/\\\?:*""<>|+=]|^[.]|[.]$"

First part [ \]\[;\/\\\?:*""<>|+=] should match any of the characters inside the brackets.

Next part ^[.] should match if the string starts with a 'dot'

Last part [.]$ should match if the string ends with a 'dot'

This works perfectly fine if I use Regex.IsMatch() function. However if I use RegularExpressionAttribute in ASP.NET MVC, I always get invalid model. Does anyone have any clue why this behavior occurs?

Examples:

"abcdefg" should not match

".abcdefg" should match

"abc.defg" should not match

"abcdefg." should match

"abc[defg" should match

Thanks in advance!

EDIT:

The RegularExpressionAttribute Specifies that a data field value in ASP.NET Dynamic Data must match the specified regular expression..

Which means. I need the "abcdef" to match, and ".abcdefg" to not match. Basically negate the whole expression I have above.

2 Answers

You need to make sure the pattern matches the entire string.

In a general case, you may append/prepend the pattern with .*.

Here, you may use

.*[ \][;/\\?:*"<>|+=].*|^[.].*|.*[.]$

Or, to make it a bit more efficient (that is, to reduce backtracking in the first branch) a negated character class will perform better:

[^ \][;/\\?:*"<>|+=]*[ \][;\/\\?:*"<>|+=].*|^[.].*|.*[.]$

But it is best to put the branches matching text at the start/end of the string as first branches:

^[.].*|.*[.]$|[^ \][;/\\?:*"<>|+=]*[ \][;/\\?:*"<>|+=].*

NOTE: You do not have to escape / and ? chars inside the .NET regex since you can't use regex delimiters there.

C# declaration of the last pattern will look like

@"^[.].*|.*[.]$|[^ \][;/\\?:*""<>|+=]*[ \][;/\\?:*""<>|+=].*"

See this .NET regex demo.

RegularExpressionAttrubute:

[RegularExpression(
  @"^[.].*|.*[.]$|[^ \][;/\\?:*""<>|+=]*[ \][;/\\?:*""<>|+=].*", 
  ErrorMessage = "Username cannot contain following characters: ] [ ; / \\ ? : * \" < > | + =")
]

Your regex is an alternation which matches 1 character out of 3 character classes, the first consisting of more than 1 characters, the second a dot at the start of the string and the third a dot at the end of the string.

It works fine because it does match one of the alternations, only not the whole string you want to match.

You could use 3 alternations where the first matches a dot followed by repeating the character class until the end of the string, the second the other way around but this time the dot is at the end of the string.

Or the third using a positive lookahead asserting that the string contains at least one of the characters [\][;\/\\?:*"<>|+=]

^\.[a-z \][;\/\\?:*"<>|+=]+$|^[a-z \][;\/\\?:*"<>|+=]+\.$|^(?=.*[\][;\/\\?:*"<>|+=])[a-z \][;\/\\?:*"<>|+=]+$

Regex demo

Related