로그인과 회원가입 페이지를 만드는 도중 이메일이나 비밀번호에 특정한 규칙을 설정해보기 위해 이글을 작성합니다.
정규 표현식(regular expression) 또는 정규식은 특정한 규칙을 가진 문자열의 집합을 표현하는데 사용하는 형식 언어(특정한 법칙들에 따라 적절하게 구성된 문자열들의 집합)이다.
위키피디아: 정규 표현식
어떤 서비스에 대해서 로그인 혹은 회원 가입을 하려면 다음과 같이 특정 규칙을 따라야 한다는 것을 겪어 보셨을 것입니다.

이 사진은 번역 서비스를 제공하는 플리토 앱의 회원가입 페이지 입니다.
위와 같이 원하는 조건을 걸어주기 위해 정규 표현식을 알아보겠습니다.
| 제목 | 설명 |
|---|---|
| ^ | 시작 앵커 |
| $ | 끝 앵커 |
| {n} | 문자열 길이: n |
| {n,} | 문자열 길이: n이상 |
| {n,m} | 문자열 길이: n이상, m이하 => {n, m}처럼 ,(콤마)사이에는 공백이 없어야 됩니다. |
| [a-z] | 영어 소문자 |
| [A-Z] | 영어 대문자 |
| [0-9] 또는 \d | 숫자 |
| [A-Za-z] | 대문자 + 소문자 |
| [A-Za-z0-9] | 대문자 + 소문자 + 숫자 |
| [~!@#$%^&*] | 특수 문자 => 원하는 특수문자 작성 |
| (?=.*[조건]) | 최소 하나 이상의(조건) |
| (?=.*[A-Z]) | 하나 이상의 대문자 포함 |
| (?=.*[A-Z].*[A-Z]) | 두개 이상의 대문자 포함 => (?=.*[A-Z]{2}) 다음과 같이 작성하면 대문자가 연속으로 2번 나와야 되는 것입니다. |
간단한 예제를 들고 해당 정규 표현식이 어떤 의미로 작성되었는지 분석해보겠습니다.
let emailRegex = "^[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z]{2,}$"
let passwordRegex = "^(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"
지금 코드를 보면 문자열을 사용하여 정규 표현식을 정의하고 있습니다. 그런데 raw 문자열 리터럴을 사용하여 정규 표현식을 정의할수 있습니다. raw 문자열 리터럴이란 Swift 5.0에서 도입된 기능으로, 문자열 내의 이스케이프 문자를 해석하지 않고 문자 그대로 처리하는 문자열 표기법입니다.
따라서 위 두 코드를 다음과 같이 표현해도 같은 로직이 작동합니다.
let emailRegex = #"^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]{2,}$"# let passwordRegex = #"^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"#

NSPredicate는 클래스로 CoreData에서 특정 데이터를 가져올때 사용하거나, NSPredicate의 메소드인 evaluate(with:)을 사용하여 정규식을 판별하기 위해 사용하는 할 수 있습니다. 정규식을 판별하기 위해 NSPredicate를 사용하겠습니다.

init(foramt:)는 문자열 형식의 조건을 사용하여 NSPredicate 객체를 생성하는 메서드입니다. 이 메서드는 조건을 나타내는 형식 문자열과 선택적으로 해당 형식 문자열에 포함될 변수를 인자로 받습니다.

evaluate메소드는 우리가 지정한 개체가 predicate에서 지정한 조건과 일치하는지 여부를 bool타입으로 반환하여 알려줍니다.
import Foundation
func validateEmail(email: String) -> Bool {
let emailRegex = #"^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]{2,}$"#
let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
return emailPredicate.evaluate(with: email)
}
let email = "example@example.com"
print(validateEmail(email: email)) // true
let email2 = "example@example."
print(validateEmail(email: email2)) // false
let emailRegex = #"^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]{2,}$"#
이메일 주소의 정규 표현식을 나타냅니다.
let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
NSPredicate(format:)를 사용하여 문자열 형식의 조건을 NSPredicate로 변환합니다.
여기서 "SELF MATCHES"를 사용하여 문자열이 정규 표현식과 일치하는지를 확인하는 NSPredicate 객체를 생성합니다.NSPredicate의 format속 문자를 살펴보면 "SELF MATCHES %@"라고 표현이 되어 있는 것을 확인할 수 있습니다. 여기서 %@는 Objective-C에서 사용하는 형식 지정자인 문자열을 뜻합니다.
let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)우리가 코드에서 넣어준 emailRegex를 저 %@자리에 들어가게 됩니다. 해당 %@자리에 직접적으로 Regex 문자열을 적어도 상관없습니다.
return emailPredicate.evaluate(with: email)
evaluate(with:) 메소드를 사용하여 NSPredicate가 주어진 문자열(email)과 일치하는지 여부를 확인합니다.
만약 주어진 이메일 주소가 정규 표현식에 맞는 형식이라면 true를 반환하고, 그렇지 않으면 false를 반환합니다.
참고
https://developer.apple.com/documentation/foundation/nspredicate
https://developer.apple.com/documentation/foundation/nspredicate/3126726-init
https://developer.apple.com/documentation/foundation/nspredicate/1417924-evaluate
https://ios-development.tistory.com/591
https://velog.io/@simh3077/Regex-Explanation-with-NSPredicate