이전에 제공된 모든 답변은 동일한 (올바른) 기술을 사용하여 각 요구 사항에 대해 별도의 미리보기를 사용합니다. 그러나 실제로 암호를 사용할 백엔드에 따라 몇 가지 비효율 성과 잠재적으로 대규모 버그가 있습니다.
수락 된 답변에서 정규식으로 시작하겠습니다.
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
우선, Java 는 .NET과 독립적으로 전체 문자열의 유효성을 검사하기 위해 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
점은 실제로 어떤 문자를 허용하려는 경우에만 사용해야합니다. 그렇지 않으면 (부정 된) 문자 클래스를 사용하여 정규식을 실제로 허용되는 문자로만 제한하십시오. 이 경우에는 별 차이가 없지만 다른 것이 더 적절할 때 점을 사용하지 않는 것은 아주 좋은 습관입니다. 개발자가 점보다 더 적절한 것을 사용하기에는 너무 게으 르기 때문에 엄청난 역 추적 사례가 너무 많습니다 .
초기 테스트에서 암호의 전반부에서 적절한 문자를 찾을 가능성이 높기 때문에 lazy quantifier가 더 효율적일 수 있습니다.
\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z
그러나 이제 정말 중요한 문제에 대해 설명합니다. 원래 질문이 ASCII로 생각하는 사람이 작성한 것처럼 보인다는 사실에 대한 답변은 없습니다. 그러나 Java에서 문자열은 유니 코드입니다. 비 ASCII 문자가 비밀번호에 허용됩니까? 그럴 경우 ASCII 공백 만 허용되거나 모든 유니 코드 공백을 제외해야합니다.
기본적으로 \s
ASCII 공백 만 일치하므로 그 역 \S
은 모든 유니 코드 문자 (공백 여부) 및 모든 비 공백 ASCII 문자와 일치합니다. 유니 코드 문자는 허용되지만 유니 코드 공백은 허용되지 않는 경우 유니 코드 공백 UNICODE_CHARACTER_CLASS
을 \S
제외 하도록 플래그를 지정할 수 있습니다 . 유니 코드 문자가 허용 되지 않으면 공백이나 제어 문자가 아닌 모든 ASCII 문자를 일치시키는 [\x21-\x7E]
대신 사용할 수 있습니다 \S
.
다음으로 잠재적 인 문제가 있습니다. 제어 문자를 허용 하시겠습니까? 적절한 정규식을 작성하는 첫 번째 단계는 일치하려는 항목과 일치하지 않는 항목을 정확하게 지정하는 것입니다. 기술적으로 유일한 100 % 정답은 제어 문자 또는 비 ASCII 문자와 같은 특정 범위의 문자가 허용되는지 여부를 나타내지 않기 때문에 질문의 암호 사양이 모호하다는 것입니다.