Stop it. Just stop it. Unless you have some kind of unusual performance requirements, keep it simple:
/// <summary>
/// Regular expression pattern that matches strings containing only Unicode
/// letters, digits, and hyphens.
/// </summary>
public static Regex UnicodeLettersNumsHyphenAllUnicodeLettersNumsHyphen = new Regex(@"^[\p{L}\p{Nd}-]+$"]*$");
public static bool IsValid(string s)
{
return (
s.Length >= 6 && s.Length <= 16
&& UnicodeLettersNumsHyphenAllUnicodeLettersNumsHyphen.IsMatch(s)
&& s.Count(c => c == '-') <= 1
&& Char.IsLetter(s, 0)
&& s[s.Length - 1] != '-'
);
}
(Those parentheses are optional. I find them visually appealing. Follow your group's coding guidelines on style choices like that.)
Given the requirements you specify, there's no reason for loops, extension methods, or any of that stuff. I promise you that 2 years down the line, anyone reading this code (including you!) will be much happier understanding the 5 liner than your code. The smaller the scope the better when you're reading. It will take someone 30 seconds to fully understand these 6 lines of code. It will take 10 minutes to dive through all yours.
And this isn't any less flexible. In fact it's more so. You can trivially add new rules to this 6 line method. That is not the case with your code. Your patterns require adding 20 extra lines of boilerplate that then has to be tested and presents more opportunities for mistakes.
And look how I dealt with the regular expression impenetrability:
- Encode as many rules as possible outside the regex.
- Only use one fairly simple, appropriately named and documented regex for just the one check: that it matches the character classes. That and maybe a comment are all you need.
If you are completely dead set against regular expressions, consider this LINQ based alternative:
public static bool IsValid(string s)
{
return (
s.Length >= 6 && s.Length <= 16
&& s.All(c => Char.IsLetterOrDigit(c) || '-' == c)
&& s.Count(c => c == '-') <= 1
&& Char.IsLetter(s, 0)
&& s[s.Length - 1] != '-'
);
}