以前に与えられたすべての回答は、同じ(正しい)手法を使用して、要件ごとに個別の先読みを使用します。しかし、実際にはパスワードを使用するバックエンドに応じて、いくつかの非効率性と潜在的に大規模なバグが含まれています。
受け入れられた答えの正規表現から始めます:
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
Javaサポートしているため、すべての最初に、\A
と\z
私は独立の、必ず文字列全体が検証されていることを確認するために、これらを使用することを好みますPattern.MULTILINE
。これはパフォーマンスには影響しませんが、正規表現がリサイクルされるときの間違いを回避します。
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z
パスワードに空白が含まれていないことの確認とその最小長の確認は、許可される文字を制限する{8,}
略記に可変数量詞を置くことにより、一度にすべてのパスを使用し\S
て実行できます。
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])\S{8,}\z
提供されたパスワードにスペースが含まれている場合、すべてのチェックが実行され、スペースの最終チェックが失敗するだけです。これは、すべてのドットを\S
次のように置き換えることで回避できます。
\A(?=\S*[0-9])(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[@#$%^&+=])\S{8,}\z
ドットは、本当に文字を許可したい場合にのみ使用してください。それ以外の場合は、(否定された)文字クラスを使用して、正規表現を本当に許可されている文字のみに制限します。この場合、それはほとんど違いがありませんが、他のより適切なときにドットを使用しないことは非常に良い習慣です。ドットよりも適切なものを使用するのに開発者が怠惰だったため、壊滅的なバックトラッキングのケースが多すぎます。
最初のテストでパスワードの前半に適切な文字が見つかる可能性が高いため、遅延量指定子の方が効率的です。
\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z
しかし、ここで本当に重要な問題について説明します。いずれの回答も、元の質問がASCIIで考える誰かによって書かれたように見えるという事実について言及していません。しかし、Javaの文字列はUnicodeです。パスワードに非ASCII文字を使用できますか?そうである場合は、ASCIIスペースのみが許可されていないか、すべてのUnicode空白を除外する必要があります。
デフォルト\s
では、ASCIIの空白のみと一致するため、その逆は\S
すべてのUnicode文字(空白かどうか)と空白以外のすべてのASCII文字と一致します。Unicode文字は許可されているがUnicodeスペースは許可されていない場合は、UNICODE_CHARACTER_CLASS
フラグを指定して\S
Unicode空白を除外できます。Unicode文字が許可されていない場合は、[\x21-\x7E]
代わりに使用\S
して、スペースまたは制御文字ではないすべてのASCII文字を照合できます。
これにより、次の潜在的な問題が発生します。制御文字を許可しますか?適切な正規表現を作成する最初のステップは、一致させたいものと一致させないものを正確に指定することです。唯一の100%技術的に正しい答えは、制御文字や非ASCII文字などの特定の範囲の文字が許可されているかどうかが記載されていないため、質問のパスワードの指定があいまいであることです。