Frage Regex Match 2 von 4 Gruppen


Ich möchte, dass ein einzelner Regex-Ausdruck zwei Gruppen von Kleinbuchstaben, Großbuchstaben, Zahlen oder Sonderzeichen abgleicht. Die Länge muss auch größer als 7 sein.

Ich habe derzeit diesen Ausdruck

^(?=.*[^a-zA-Z])(?=.*[a-z])(?=.*[A-Z]).{8,}$

Es erzwingt jedoch, dass die Zeichenfolge Groß- und Kleinbuchstaben und Ziffern oder Sonderzeichen enthält.

Ich habe dies zur Zeit implementiert mit 4 verschiedenen Regex-Ausdrücke, die ich mit einigen C # -Code abfragen.

Ich plane, denselben Ausdruck in JavaScript wiederzuverwenden.

Dies ist eine Beispielkonsolen-App, die den Unterschied zwischen zwei Ansätzen zeigt.

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

5
2017-12-03 00:06


Ursprung


Antworten:


Für JavaScript können Sie dieses Muster verwenden, das nach Grenzen zwischen verschiedenen Zeichenklassen sucht:

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

Wenn eine Grenze gefunden wird, sind Sie sicher, zwei verschiedene Klassen zu haben.

Musterdetails:

\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.

Grenze zwischen einem Buchstaben und einer Zahl:

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

Grenze zwischen einem Großbuchstaben und einem Kleinbuchstaben:

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

Da alle Änderungen mindestens zwei Zeichen aus zwei verschiedenen Zeichenklassen enthalten, erhalten Sie das gewünschte Ergebnis.


2
2017-12-03 01:01



Sie könnten Possessiv-Quantoren verwenden (emuliert mit Atomgruppen), etwa so:

((?>[a-z]+)|(?>[A-Z]+)|(?>[^a-zA-Z]+)){2,}

Da die Verwendung von Possessiv-Matching das Zurückverfolgen verhindert, werden Sie nicht auf die zwei Gruppen stoßen, die beispielsweise aus zwei aufeinanderfolgenden Kleinbuchstaben bestehen. Die volle Regex wäre also so etwas wie:

^(?=.*((?>[a-z]+)|(?>[A-Z]+)|(?>[^a-zA-Z]+)){2,}).{8,}$

Obwohl ich es wäre, würde ich den Lookahead schneiden, benutze einfach den Ausdruck ((?>[a-z]+)|(?>[A-Z]+)|(?>[^a-zA-Z]+)){2,}und überprüfen Sie die Länge separat.


1
2017-12-03 00:28