동아리 프로젝트 중, 비밀번호 변경을 구현하는 단계에서 정규식을 사용할 일이 생겼습니다.
조건은 '영문, 숫자, 특수문자 중 2개를 사용하여 최소 8자리 이상'의 비밀번호를 입력해야 합니다.
자바와 코틀린에서는 기본적으로 Pattern과 Matcher라는 정규식 라이브러리 클래스를 제공합니다.
이번 포스팅에서는 해당 클래스의 사용방법에 대해 알아보고 직접 비밀번호에 적용해보도록 하겠습니다.
Pattern
- Pattern 클래스 주요 메서드
compile(String regex) : 주어진 정규표현식으로부터 패턴을 만듭니다.
matcher(CharSequence input) : 대상 문자열이 패턴과 일치할 경우 true를 반환합니다.
asPredicate() : 문자열을 일치시키는 데 사용할 수있는 술어를 작성합니다.
pattern() : 컴파일된 정규표현식을 String 형태로 반환합니다.
split(CharSequence input) : 문자열을 주어진 인자값 CharSequence 패턴에 따라 분리합니다.
- Parttern 플래그 값 사용(상수)
Pattern.CANON_EQ : None표준화된 매칭 모드를 활성화합니다.
Pattern.CASE_INSENSITIVE : 대소문자를 구분하지 않습니다.
Pattern.COMMENTS : 공백과 #으로 시작하는 주석이 무시됩니다. (라인의 끝까지).
Pattern.MULTILINE : 수식 ‘^’ 는 라인의 시작과, ‘$’ 는 라인의 끝과 match 됩니다.
Pattern.DOTALL : 수식 ‘.’과 모든 문자와 match 되고 ‘\n’ 도 match 에 포함됩니다.
Pattern.UNICODE_CASE : 유니코드를 기준으로 대소문자 구분 없이 match 시킵니다.
Pattert.UNIX_LINES : 수식 ‘.’ 과 ‘^’ 및 ‘$’의 match시에 한 라인의 끝을 의미하는 ‘\n’만 인식됩니다.
Matcher
- Matcher 클래스 주요 메서드
matches() : 대상 문자열과 패턴이 일치할 경우 true 반환합니다.
find() : 대상 문자열과 패턴이 일치하는 경우 true를 반환하고, 그 위치로 이동합니다.
find(int start) : start위치 이후부터 매칭검색을 수행합니다.
start() : 매칭되는 문자열 시작위치 반환합니다.
start(int group) : 지정된 그룹이 매칭되는 시작위치 반환합니다.
end() : 매칭되는 문자열 끝 다음 문자위치 반환합니다.
end(int group) : 지정되 그룹이 매칭되는 끝 다음 문자위치 반환합니다.
group() : 매칭된 부분을 반환합니다.
group(int group) : 매칭된 부분중 group번 그룹핑 매칭부분 반환합니다.
groupCount() : 패턴내 그룹핑한(괄호지정) 전체 갯수를 반환합니다.
MetaCharacter
표현식 | 설명 |
^ | 문자열의 시작 |
$ | 문자열의 종료 |
. | 임의의 한 문자 (문자의 종류 가리지 않음, 단, \ 는 넣을 수 없음) |
* | 앞 문자가 없을 수도 무한정 많을 수도 있음 |
+ | 앞 문자가 하나 이상 |
? | 앞 문자가 없거나 하나있음 |
[] | 문자의 집합이나 범위를 나타내며 두 문자 사이는 - 기호로 범위를 나타낸다. []내에서 ^가 선행하여 존재하면 not 을 나타낸다. |
{} | 횟수 또는 범위를 나타낸다. |
() | 소괄호 안의 문자를 하나의 문자로 인식 |
| | 패턴 안에서 or 연산을 수행할 때 사용 |
\s | 공백 문자 |
\S | 공백 문자가 아닌 나머지 문자 |
\w | 알파벳이나 숫자 |
\W | 알파벳이나 숫자를 제외한 문자 |
\d | 숫자 [0-9]와 동일 |
\D | 숫자를 제외한 모든 문자 |
\ | 정규표현식 역슬래시(\)는 확장 문자. 역슬래시 다음에 일반 문자가 오면 특수문자로 취급하고 역슬래시 다음에 특수문자가 오면 그 문자 자체를 의미 |
(?i) | 앞 부분에 (?i) 라는 옵션을 넣어주면 대소문자를 구분하지 않음 |
정규식 패턴
분류 | 정규식 패턴 |
숫자 | ^[0-9]*$ |
영문자 | ^[a-zA-Z]*$ |
한글 | ^[가-힣]*$ |
영어&숫자 | ^[a-zA-Z0-9]*$ |
비밀번호 (숫자, 문자 포함의 6~12자리 이내) | ^[A-Za-z0-9]{6,12}$ |
비밀번호 (숫자, 문자, 특수문자 포함 8~15자리 이내) | ^.*(?=^.{8,15}$)(?=.*\d)(?=.*[a-zA-Z])(?=.*[!@#$%^&+=]).*$ |
이메일 | ^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$ |
휴대전화 | ^\\d{3}-\\d{3,4}-\\d{4}$ |
일반전화 | ^\\d{2,3}-\\d{3,4}-\\d{4}$ |
주민등록번호 | \d{6} \- [1-4]\d{6} |
파일확장자 | ^\\S+.(?i)(txt|pdf|hwp|xls)$ |
이중 파일확장자 | (.+?)((\\.tar)?\\.gz)$ |
위에 정리된 메서드와 표를 바탕으로 정규식을 만들어보겠습니다.
1. 영문과 숫자가 섞인 8 ~ 20자의 문자를 입력받기
val pwPattern1 = "^(?=.*[A-Za-z])(?=.*[0-9])[A-Za-z[0-9]]{8,20}$" // 영문, 숫자 8 ~ 20자 패턴
val password1 = "abcd1234" // 임의의 패스워드 1 (영문+숫자)
val password2 = "1234@$!*" // 임의의 패스워드 2 (숫자+특수문자)
val pattern = Pattern.compile(pwPattern1) // 패턴 컴파일
val matcher1 = pattern.matcher(password1) // 비교를 위한 Matcher 인스턴스 생성
val matcher2 = pattern.matcher(password2) // 비교를 위한 Matcher 인스턴스 생성
Log.d("Match", matcher1.find().toString()) // 패턴 비교 결과 출력
Log.d("Match", matcher2.find().toString()) // 패턴 비교 결과 출력
True
False
2. 영문과 특수문자가 섞인 8 ~ 20자의 문자를 입력받기
val pwPattern2 = "^(?=.*[A-Za-z])(?=.*[$@$!%*#?&.])[A-Za-z$@$!%*#?&.]{8,20}$" // 영문, 특수문자 8 ~ 20자 패턴
val password1 = "1234@$!*" // 임의의 패스워드 1 (숫자+특수문자)
val password2 = "abcd@$!*" // 임의의 패스워드 2 (영문+특수문자)
val pattern = Pattern.compile(pwPattern2) // 패턴 컴파일
val matcher1 = pattern.matcher(password1) // 비교를 위한 Matcher 인스턴스 생성
val matcher2 = pattern.matcher(password2) // 비교를 위한 Matcher 인스턴스 생성
Log.d("Match", matcher1.find().toString()) // 패턴 비교 결과 출력
Log.d("Match", matcher2.find().toString()) // 패턴 비교 결과 출력
False
True
3. 숫자와 특수문자 섞인 8 ~ 20자의 문자를 입력받기
val pwPattern3 = "^(?=.*[0-9])(?=.*[$@$!%*#?&.])[[0-9]$@$!%*#?&.]{8,20}$" // 숫자, 특수문자 8 ~ 20자 패턴
val password1 = "abcd1234" // 임의의 패스워드 1 (영문+숫자)
val password2 = "1234@$!*" // 임의의 패스워드 2 (숫자+특수문자)
val pattern = Pattern.compile(pwPattern3) // 패턴 컴파일
val matcher1 = pattern.matcher(password1) // 비교를 위한 Matcher 인스턴스 생성
val matcher2 = pattern.matcher(password2) // 비교를 위한 Matcher 인스턴스 생성
Log.d("Match", matcher1.find().toString()) // 패턴 비교 결과 출력
Log.d("Match", matcher2.find().toString()) // 패턴 비교 결과 출력
False
True
위와 같은 코드를 바탕으로 비밀번호의 패턴을 만들어낼 수가 있습니다.
저희 프로젝트의 패스워드 조건은 이 3가지를 모두 혼합해야 만들어낼 수 있습니다.
즉, 영문+숫자+특수문자 중 2가지를 입력받아야 하며, 글자 수는 8자 이상이어야 합니다.
해당 조건을 구현한 코드는 아래와 같습니다.
private fun isRegularPW(password: String): Boolean {
val pwPattern1 =
"^(?=.*[A-Za-z])(?=.*[0-9])[A-Za-z[0-9]]{8,20}$" // 영문, 숫자
val pwPattern2 =
"^(?=.*[0-9])(?=.*[$@$!%*#?&.])[[0-9]$@$!%*#?&.]{8,20}$" // 숫자, 특수문자
val pwPattern3 =
"^(?=.*[A-Za-z])(?=.*[$@$!%*#?&.])[A-Za-z$@$!%*#?&.]{8,20}$" // 영문, 특수문자
val pwPattern4 =
"^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%*#?&.])[A-Za-z[0-9]$@$!%*#?&.]{8,20}$" // 영문, 숫자, 특수문자
val pattern = Pattern.compile(pwPattern1)
val matcher = pattern.matcher(pwPattern1)
Log.d("Match", matcher.find().toString())
return (Pattern.matches(pwPattern1, password) ||
Pattern.matches(pwPattern2, password) ||
Pattern.matches(pwPattern3, password) ||
Pattern.matches(pwPattern4, password))
}
TextWatcher를 통해 EditText의 입력값을 감지하고, 정규식을 통해 패스워드 조건이 일치한다면 완료 버튼을 활성화합니다.
이상으로 정규식에 대한 개념을 다루어보았습니다.
아래에는 자주 사용되는 정규표현식을 정리한 표를 남기며 포스팅을 마무리하겠습니다.
긴 글 읽어주셔서 감사합니다.
자주 사용되는 정규표현식
정규 표현식 | 설명 |
^[0-9]*$ | 숫자 |
^[a-zA-Z]*$ | 영문자 |
^[가-힣]*$ | 한글 |
\\w+@\\w+\\.\\w+(\\.\\w+)? | |
^\d{2,3}-\d{3,4}-\d{4}$ | 전화번호 |
^01(?:0|1|[6-9])-(?:\d{3}|\d{4})-\d{4}$ | 휴대전화번호 |
\d{6} \- [1-4]\d{6} | 주민등록번호 |
^\d{3}-\d{2}$ | 우편번호 |
내용에 오류가 있거나, 질문이 있으신 분들은 댓글을 남겨주시면 감사하겠습니다! 😊
'Android' 카테고리의 다른 글
[Android] Listview vs RecyclerView (1) | 2023.04.20 |
---|---|
[Android] This version of the Android Support plugin for IntelliJ IDEA (or Android Studio) 오류 해결 (2) | 2022.12.23 |
[Android] ViewModel + Event Wrapper Pattern 단일 이벤트 처리 (0) | 2022.12.12 |
[Android] Firebase Dynamic Link를 활용하여 사용자 초대링크 생성하기 (2) | 2022.02.08 |
[Android][어따세워] 음성인식으로 주차장을 검색해보자! STT(Speech To Text) SpeechRecognizer (2) | 2021.12.11 |