Regex match 2 out of 4 groups

asp.net-mvc, c#, javascript, regex

Solution

For javascript you can use this pattern that looks for boundaries between different character classes:

^(?=.*(?:.\b.|(?i)(?:[a-z]\d|\d[a-z])|[a-z][A-Z]|[A-Z][a-z]))[^:\s]{8,}$

if a boundary is found, you are sure to have two different classes.

pattern details:

\b # is a zero width assertion, it's a boundary between a member of 
   # the \w class and an other character that is not from this class.

.\b. # represents the two characters with the word boundary.

boundary between a letter and a number:

(?i) # make the subpattern case insensitive
(?:
    [a-z]\d # a letter and a digit
  |         # OR
    \d[a-z] # a digit and a letter
)

boundary between an uppercase and a lowercase letter:

[a-z][A-Z] | [A-Z][a-z]

since all alternations contains at least two characters from two different character classes, you are sure to obtain the result you hope.

Problem

I want a single Regex expression to match 2 groups of lowercase, uppercase, numbers or special characters. Length needs to also be grater than 7. I currently have this expression ``` ^(?=.*[^a-zA-Z])(?=.*[a-z])(?=.*[A-Z]).{8,}$ ``` It, however, forces the string to have lowercase and uppercase and digit or special character. I currently have this implemented using 4 different regex expressions that I interrogate with some C# code. I plan to reuse the same expression in JavaScript. This is sample console app that shows the difference between 2 approaches. ``` class Program { private static readonly Regex[] Regexs = new[] { new Regex("[a-z]", RegexOptions.Compiled), //Lowercase Letter new Regex("[A-Z]", RegexOptions.Compiled), // Uppercase Letter new Regex(@"\d", RegexOptions.Compiled), // Numeric new Regex(@"[^a-zA-Z\d\s:]", RegexOptions.Compiled) // Non AlphaNumeric }; static void Main(string[] args) { Regex expression = new Regex(@"^(?=.*[^a-zA-Z])(?=.*[a-z])(?=.*[A-Z]).{8,}$", RegexOptions.ECMAScript & RegexOptions.Compiled); string[] testCases = new[] { "P@ssword", "Password", "P2ssword", "xpo123", "xpo123!", "xpo123!123@@", "Myxpo123!123@@", "Something_Really_Complex123!#43@2*333" }; Console.WriteLine("{0}\t{1}\t", "Single", "C# Hack"); Console.WriteLine(""); foreach (var testCase in testCases) { Console.WriteLine("{0}\t{2}\t : {1}", expression.IsMatch(testCase), testCase, (testCase.Length >= 8 && Regexs.Count(x => x.IsMatch(testCase)) >= 2)); } Console.ReadKey(); } } Result Proper Test String ------- ------- ------------ True True : P@ssword False True : Password True True : P2ssword False False : xpo123 False False : xpo123! False True : xpo123!123@@ True True : Myxpo123!123@@ True True : Something_Really_Complex123!#43@2*333 ```

Original source

Related problems