パスワードが「大文字1文字、特殊文字1文字、英数字を含む8文字」かどうかを確認する正規表現


102

正規表現で確認したい

パスワードは、大文字1文字、特殊文字1文字、英数字を含む8文字にする必要があります。

そして、これが私の大文字と小文字、1つの数字または特殊文字を含む8文字の検証式です。

(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$"

大文字1文字、特殊文字1文字、英数字を含む8文字のパスワードを入力するにはどうすればよいですか?


26
なぜこれに正規表現が必要なのですか?要件に一致する完全な正規表現は非常に長く複雑になります。C#コードで制約を記述する方が簡単です。
グレッグヒューギル

32
強力なパスワードの不完全なプロキシであるいくつかの任意のルールをパスワードが満たしていることを確認するのではなく、強力なパスワードを確認することを検討しましたか?多くのライブラリとプログラムがあり、パスワードを入力すると、その強さを決定します。
ウェインコンラッド

4
@GregHewgill私はできればあなたのコメントを賛成します:-)これは「ハンマーしか持っていない場合、すべてが釘のように見え始める」の別のケースのように見えます。
Christian.K

3
あなたは必要ですか、正確に 1大文字/特殊文字または少なくとも 1を?
mmdemirbas

4
ユーザーの要件によって、ユーザーが実装の詳細を指示しているということですか?おそらく、彼らはこれを自分でコーディングするだけです。正直に言うと、カウンターを作成してすべての文字を1つずつチェックし、ルールに一致するすべての文字に適切なカウンターをインクリメントすると、メンテナンスと理解が容易になると思います。技術的な観点からは、それは誰もが感心するようなものではありませんが、なぜエラーが発生しやすく更新が難しいもので物事を複雑にするのでしょうか。

回答:


132

あなたが追いかけている正規表現は、おそらく巨大であり、特に正規表現にあまり詳しくない人にとっては、維持しなければならない悪夢です。

私はあなたの正規表現を分解して一度に少しずつ行う方が簡単だと思います。少し時間がかかるかもしれませんが、メンテナンスとデバッグの方が簡単だと思います。これにより、ユーザーに(だけでなくInvalid Password)より多くの指示されたエラーメッセージを提供し、ユーザーエクスペリエンスを向上させることができます。

私があなたが正規表現にかなり流暢であることを私が見ていることから、私はあなたが必要とすることをするためにあなたに正規表現を与えることは無駄であろうと思います。

あなたのコメントを見て、これは私がそれについてどうするかです:

  • 長さは8文字である必要があります。これには正規表現は必要ありません。.Lengthプロパティを使用するだけで十分です。

  • 大文字を1つ含める:[A-Z]+正規表現を使用できます。文字列に少なくとも1つの大文字が含まれている場合、この正規表現はを生成しtrueます。

  • 1つの特殊文字:\W文字または数字以外の任意の文字に一致するを使用できます。または、[!@#]特殊文字のカスタムリストを指定するためにそのようなものを使用できます。注など、その文字けれども$^()彼らはそうのようにエスケープする必要があるので、正規表現言語で特殊文字です:\$。要するに、あなたはを使うかもしれません\W

  • 英数字:の使用は、\w+任意の文字と数字、およびアンダースコアに一致する必要があります。

詳細については、このチュートリアルをご覧ください。


2
私はこれを書いていない私は自分のグーグル親愛なる友人からそれを手に入れました
Rania Umair

4
@RaniaUmair:あなたのコメントは私の主張を証明していると思います。私が指定したようにそれを分解することをお勧めします。
npinti

35
+1
正規表現

@ w0lf:私はこれ以上同意できませんでした。Regexは強力ですが、複雑すぎて速くなりすぎないため、シンプルに保つことをお勧めします。
npinti

少なくとも1つの数値を受け入れるregxが必要で、他の最大3つの文字は何でもかまいません
Lijo

107
(                   # Start of group
    (?=.*\d)        #   must contain at least one digit
    (?=.*[A-Z])     #   must contain at least one uppercase character
    (?=.*\W)        #   must contain at least one special symbol
       .            #     match anything with previous condition checking
         {8,8}      #        length is exactly 8 characters
)                   # End of group

1行で:

((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})

2019-05-28を編集:

入力文字列全体と一致する必要があります。したがって、との間に正規表現を入れて^$部分一致が入力全体と一致すると誤って想定しないようにすることができます。

^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$

出典:


58
12文字で構成されているため
mmdemirbas 2013

もう1つの条件が数字で始まってはいけません。どうすればよいですか?
リジョ14

7
代わりに{8}を使用して8文字に一致させることができます
アンジェロトリカリコ'22

$ 1eerrrrrrrに一致します。大文字はありません。
Shilpi Jaiswal

@ShilpiJaiswal大文字と小文字を区別しない一致のためにフラグを使用しているか、または「一致」の代わりに「検索」を行っています。入力文字列全体と確実に一致させるには、^との間に正規表現を含めることができます$。これを試してください:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
mmdemirbas

35

非常に多くの答え....すべて悪い!

正規表現にはAND演算子がないので、有効性が何かAND何かAND何かで定義されている場合、有効なパスワードに一致する正規表現を書くのはかなり困難です...

ただし、正規表現に OR演算子があるため、DeMorganの定理を適用し、無効なパスワードに一致する正規表現を記述します。

8文字未満で何かORなしの数字を使って何ORなしの大文字で何かOR特殊文字を使って何

そう:

^(.{0,7}|[^0-9]*|[^A-Z]*|[a-zA-Z0-9]*)$

一致するものがあれば、それは無効なパスワードです。


3
OPで正確に8文字が必要な場合は、を追加する必要があります|.{9,}。コンセプトの+1
Daniel

単一の正規表現は実際の問題に最適なものではないことに同意しますが、問題に対する素晴らしく単純な解決策です。
Siderite Zackwehdex

1
正規表現に AND演算子があり、先読み/後読みアサーションと呼ばれます。
relative_random

13

答えは、正規表現を使用しないことです。これはセットとカウントです。

正規表現は順序に関するものです。

プログラマーとしてのあなたの人生では、意味のない多くのことをするように求められます。レベルを深く掘り下げることを学びます。質問が間違っている場合をご覧ください。

質問(正規表現について言及している場合)は誤りです。

疑似コード(多すぎる言語に切り替えたので、最近):

if s.length < 8:
    return False
nUpper = nLower = nAlphanum = nSpecial = 0
for c in s:
    if isUpper(c):
        nUpper++
    if isLower(c):
        nLower++
    if isAlphanumeric(c):
        nAlphanum++
    if isSpecial(c):
        nSpecial++
return (0 < nUpper) and (0 < nAlphanum) and (0 < nSpecial)

上記のコードをほぼ瞬時に読んで理解したに違いありません。正規表現の方がはるかに時間がかかったに違いないが、それが正しいことは確かではない。正規表現を拡張することは危険です。すぐ上を拡張しましたが、はるかに少なくなりました。

また、質問の表現が不正確であることに注意してください。文字セットはASCIIまたはUnicodeですか、それとも?? 質問を読んだときの私の推測では、少なくとも1つの小文字が想定されています。したがって、想定される最後のルールは次のようになります。

return (0 < nUpper) and (0 < nLower) and (0 < nAlphanum) and (0 < nSpecial)

(帽子をセキュリティ重視に変えると、これは本当に煩わしい/役に立たないルールです。)

質問が間違っていることを知ることは、賢い答えよりもはるかに重要です。間違った質問に対する賢い答えはほとんど常に間違っています。


2
同意する。作業する人が増えるほど、より多くのコードを読みやすくする必要がありますが、答えがはっきりしているので、私が見たいくつかの正規表現の実装
Nicola Peluchetti

あなたのような一部のユーザーは、Regexは常に適用するのに優れたソリューションであるとは限らず、簡単なプログラミングの方が読みやすいと言う勇気があることを気に入っています。
schlebe

12

例として、これが可読/保守可能な正規表現でどのように実行できるかを示します。

より長い正規表現RegexOptions.IgnorePatternWhitespaceでは、読みやすくするために式で空白とコメントを許可するために常に使用する必要があります。

String[] passwords = { "foobar", "Foobar", "Foobar1", "Fooobar12" };

foreach (String s in passwords) {

    Match password = Regex.Match(s, @"
                                      ^              # Match the start of the string
                                       (?=.*\p{Lu})  # Positive lookahead assertion, is true when there is an uppercase letter
                                       (?=.*\P{L})   # Positive lookahead assertion, is true when there is a non-letter
                                       \S{8,}        # At least 8 non whitespace characters
                                      $              # Match the end of the string
                                     ", RegexOptions.IgnorePatternWhitespace);

    if (password.Success) {
        Console.WriteLine(s + ": valid");
    }
    else {
        Console.WriteLine(s + ": invalid");
    }
}

Console.ReadLine();

これは、lookahead assertionある種の「and」パターンを悪用して、1つの正規表現内の制約全体をカバーするための最良の方法です。より多くの制約に対して機能し、構成によっていくつかの制約を有効/無効にする必要がある場合に簡単に生成できます。
ドッグノーズ2015

2
Unicodeカテゴリの使用は優れたアイデアです。世界はアスキーより広いです!
Walter Tross

1

大文字と特殊文字が1つだけ必要な場合は、これでうまくいくはずです。

@"^(?=.{8,}$)(?=[^A-Z]*[A-Z][^A-Z]*$)\w*\W\w*$"

文字列AAaaaaaaa#はこの表現によればOKではありません
Cristian Lupascu

3
...まあ、それはない8文字の長、10であり、それは失敗する必要がありますので、後者つ以上の大文字が含まれています
user1096188

4
あなたは正しい、それ質問でこれを言ってます。これらのルールは、大文字1つだけ」ではなく、大文字1つ以上」に近いと思いました。それがOPが望んでいたものかどうかはわかりません。
クリスティアンルパスク


0

この質問は口コミで広がり、興味深い提案がたくさん出てきました。

はい、手で書くのは難しいです。したがって、より簡単な解決策は、テンプレートを使用することです。結果の正規表現は最適ではないかもしれませんが、保守や変更が簡単になり、ユーザーは結果をより適切に制御できます。私は何かを逃した可能性があるので、建設的な批判は役に立ちます。

このリンクは興味深いかもしれません:文字列正規表現言語キャプチャグループ内の任意の順序で少なくとも2桁2文字に一致

私は(?=(?:.*?({type})){({count})})SOで見たすべての正規表現に基づいてこのテンプレートを使用しています。次のステップでは、必要なパターン(numberspecial character...)を置き換え、長さの構成を追加します。

正規表現PasswordRegexGenerator.csを構成するための小さなクラスを作成しました 。例:

string result = new PasswordRegexGenerator ( )
        .UpperCase ( 3, -1 )    // ... {3,}
        .Number ( 2, 4 )        // ... {2,4}
        .SpecialCharacter ( 2 ) // ... {2}
        .Total ( 8,-1 )
        .Compose ( );

/// <summary>
/// Generator for regular expression, validating password requirements.
/// </summary>
public class PasswordRegexGenerator
{
    private string _elementTemplate = "(?=(?:.*?({type})){({count})})";

    private Dictionary<string, string> _elements = new Dictionary<string, string> {
        { "uppercase", "[A-Z]" },
        { "lowercase", "[a-z]" },
        { "number", @"\d" },
        { "special", @"\W" },
        { "alphanumeric", @"\w" }
    };

    private StringBuilder _sb = new StringBuilder ( );

    private string Construct ( string what, int min, int max )
    {
        StringBuilder sb = new StringBuilder ( _elementTemplate );
        string count = min.ToString ( );

        if ( max == -1 )
        {
            count += ",";
        }
        else if ( max > 0 )
        {
            count += "," + max.ToString();
        }

        return sb
            .Replace ( "({type})", what )
            .Replace ( "({count})", count )
            .ToString ( );
    }

    /// <summary>
    /// Change the template for the generation of the regex parts
    /// </summary>
    /// <param name="newTemplate">the new template</param>
    /// <returns></returns>
    public PasswordRegexGenerator ChangeRegexTemplate ( string newTemplate )
    {
        _elementTemplate = newTemplate;
        return this;
       }

    /// <summary>
    /// Change or update the regex for a certain type ( number, uppercase ... )
    /// </summary>
    /// <param name="name">type of the regex</param>
    /// <param name="regex">new value for the regex</param>
    /// <returns></returns>
    public PasswordRegexGenerator ChangeRegexElements ( string name, string regex )
    {
        if ( _elements.ContainsKey ( name ) )
        {
            _elements[ name ] = regex;
        }
        else
        {
            _elements.Add ( name, regex );
        }
        return this;
    }

    #region construction methods 

    /// <summary>
    /// Adding number requirement
    /// </summary>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    public PasswordRegexGenerator Number ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "number" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator UpperCase ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "uppercase" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator LowerCase ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "lowercase" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator SpecialCharacter ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "special" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator Total ( int min, int max = 0 )
    {
        string count = min.ToString ( ) + ( ( max == 0 ) ? "" : "," + max.ToString ( ) );
        _sb.Append ( ".{" + count + "}" );
        return this;
    }

    #endregion

    public string Compose ()
    {
        return "(" + _sb.ToString ( ) + ")";
    }
}

0

以下のクラスを検証に使用できます。

public class PasswordValidator{

  private Pattern pattern;
  private Matcher matcher;

  private static final String PASSWORD_PATTERN =
          "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})";

  public PasswordValidator(){
      pattern = Pattern.compile(PASSWORD_PATTERN);
  }

  /**
   * Validate password with regular expression
   * @param password password for validation
   * @return true valid password, false invalid password
   */
  public boolean validate(final String password){

      matcher = pattern.matcher(password);
      return matcher.matches();

  }
}

ここで、6と20はパスワードの最小長と最大長です。


0
  • パスワードが8文字以上である場合、最初にパスワード全体を照合するために非バックトラッキング式を使用します(このようにして、長いが無効なパスワードの組み合わせによる爆発はありません)。 (?>{8,})
  • 後読みアサーションを使用して、必要なすべての文字(AND条件)の存在を確認します。 (?<=...)
  • 少なくとも1つの大文字: (?<=\p{Lu}.*)
  • 少なくとも1つの特殊文字(少しあいまいですが、not-wordを使用しましょう): (?<=\W.*)
  • 少なくとも1つの英数字(: (?<=\w.*)

要約する:

(?>.{8,})(?<=\p{Lu}.*)(?<=\W.*)(?<=\w.*)


0

すべてが正規表現を使用しないことが最善です。これらの要件は非常に軽いものです。基準/検証をチェックするためのCPUごとの文字列操作は、正規表現よりもはるかに安価で高速です!


-2
/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/

15
質問を編集し、説明を含めることをお勧めします。コードのみの回答で十分な場合もありますが、コード+説明の回答は常に優れています
Barranka
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.