슈프림 블로그
[Swift] 코딩테스트 보다가 열 받아서 정리하는 Swift 정규식 - NSRegularExpression (Regex) 본문
[Swift] 코딩테스트 보다가 열 받아서 정리하는 Swift 정규식 - NSRegularExpression (Regex)
_슈프림 2021. 3. 21. 20:27문자열 문제 진짜 어렵다!!!!!!!!!
매번 구글링 하지 말고 정리해 둬야 겠다는 필요성을 느꼈다...
Swift 주의사항
문자열에서 역슬래쉬(\
)는 연산자 역할을 하므로, \
를 문자 자체로 사용하고 싶은 경우에는 "\\
" 처럼 두 번 사용해야 한다.
=> 이거,, 매번 눈 빠지게 1개씩 썼는지 2개씩 썼는지 확인하지 말고 자동 변환해주는 프로그램을 하나 만들까....?ㅠㅠ
Swift 정규식 사용 방법
🐶 문자열 일부가 일치하는지 확인하는 법 (첫번째로 일치하는 부분)
이 방법은 문자열에서 정규식과 일치하는 모든 부분을 구할 수는 없다.
가장 첫번째로 일치하는 부분만 구할 수 있기 때문이다.
NSRegularExpression.firstMatch 를 사용하기도 하지만, 나는 아래 방법이 더 편리한 것 같다.
// string: 정규식과 비교할 문자열
// regex: 정규식 문자열
string.range(of: regex, options: .regularExpression)
string
에 regex
와 일치하는 부분이 있다면 가장 첫번째로 일치하는 부분의 Range<Index>
값이 나온다.
일치하는 부분이 없다면 결과가 nil이 나온다.
Optional이기 때문에 언랩핑하여 string[range]
와 같이 활용할 수 있다.
예시
문자열에 숫자가 포함되어있는지 확인하는 방법은 다음과 같다.
let strings: [String] = ["abc", "123", "ab12cd34"]
let pattern: String = "[0-9]*"
for string in strings {
guard let range = string.range(of: pattern, options: .regularExpression) else {
print("\(string)에는 숫자가 없습니다.")
continue
}
print("\(string)에서 숫자로 이루어 진 부분은 \(string[range]) 입니다.") // 가장 앞에 일치하는 부분만 확인 가능
}
abc에는 숫자가 없습니다.
123에서 숫자로 이루어 진 부분은 123입니다.
ab12cd34에서 숫자로 이루어 진 부분은 12입니다.
🐶 문자열 전체가 일치하는지 확인하는 법
위 방법과 동일하지만, 정규식 앞, 뒤에 ^
와 $
를 붙여주면 된다.
let strings: [String] = ["abc", "123", "ab12cd34"]
let pattern: String = "^[0-9]*$"
for string in strings {
guard let _ = string.range(of: pattern, options: .regularExpression) else {
print("\(string)은 숫자로만 이루어지지 않았습니다.")
continue
}
print("\(string)은 숫자로만 이루어져 있습니다.")
}
abc은 숫자로만 이루어지지 않았습니다.
123은 숫자로만 이루어져 있습니다.
ab12cd34은 숫자로만 이루어지지 않았습니다.
🐶 일치하는 모든 범위를 알아야 하는 경우
NSRegularExpression을 사용할 때는 try?
또는 do try catch
문을 사용해주어야 한다.
do {
let regex = try NSRegularExpression(pattern: pattern, options: [])
let result = regex.matches(in: string, options: [], range: NSRange(location: 0, length: string.count))
let rexStrings = result.map { (element) -> String in
let range = Range(element.range, in: string)!
return String(string[range])
}
return rexStrings
} catch let error {
print(error.localizedDescription)
}
pattern: 정규식으로 사용할 문자열
regex: pattern을 정규식으로 변환
result: string에서 regex와 일치하는 부분들 (배열) -> map을 사용하여 Range<Index>, 또는 String 배열로 변환하여 활용할 수 있다.
+ matches()
대신 firstMatch()
를 사용하면 가장 첫번째로 일치하는 부분만 구해낼 수도 있다.
🐶 그룹으로 묶인 문자열에 이름을 붙여줄 수도 있다.
정규식을 통해 찾고 싶은 문자열에 대한 이름을 붙여주고, 그 이름으로 찾는 방법이다!
그룹이란, 괄호를 통해 묶인 부분을 말한다. 그룹에는 이름을 붙여줄 수 있다.
괄호 안의 처음에 ?<name>
과 같은 형태로 적어주면 된다.
let pattern: String = "(?<name>......)"
pattern
과 일치한 부분 중 이름이 지정된 부분을 찾고 싶으면 NSTextCheckingResult.range(withName:)
을 사용한다.
result.range(withName: "name")
예시
문자열에서 yyyy.mm.dd의 날짜 형식을 모두 찾아내고
각 찾아낸 결과값에서 year, month, date를 찾는 방법!
let string: String = "기간은 2021.03.01 부터 2021.03.31까지 입니다."
let datePattern: String = "(?<year>(19|20)[0-9]{2})\\.(?<month>(0[1-9]|1[0-2]))\\.(?<date>(0[1-9]|1[0-9]|2[0-9]|3[0-1]))"
let regex = try? NSRegularExpression(pattern: datePattern, options: [])
if let result = regex?.matches(in: string, options: [], range: NSRange(location: 0, length: string.count)) {
let rexStrings = result.map { (element) -> String in
let yearRange = Range(element.range(withName: "year"), in: string)!
let monthRange = Range(element.range(withName: "month"), in: string)!
let dateRange = Range(element.range(withName: "date"), in: string)!
return "\(string[yearRange])년 \(string[monthRange])월 \(string[dateRange])일"
}
print(rexStrings)
}
["2021년 03월 01일", "2021년 03월 31일"]
자주 쓰는 정규식
대문자로만 구성
"^[A-Z]*$"
소문자로만 구성
"^[a-z]*$"
숫자로만 구성
"^[0-9]*$"
"^[\\d]*$"
// 반대 (숫자 제외)
"^[\\D]*$"
알파벳 + 숫자로만 구성
"^[0-9a-zA-Z]*$"
"^[\\w]*$"
// 반대 (알파벳, 숫자 제외)
"^[\\W]*$"
응용))) 숫자, 알파벳, 특수문자 (~!@#$%^&*) 로만 구성
"^[0-9a-zA-Z~!@#\\$%\\^&\\*]*$"
"^[\\w~!@#\\$%\\^&\\*]*$"
최소 하나 이상의 something
"(?=.*[something])"
응용) 최소 하나 이상의 대문자, 하나 이상의 소문자, 하나 이상의 숫자
"(?=.*[A-Z])(?=.*[a-z])(?=.*[\\d])"
응용2) 최소 하나 이상의 대문자, 하나 이상의 소문자, 하나 이상의 숫자, 하나 이상의 특수문자(~!@#$%^&*), 그 외 불포함
"^(?=.*[A-Z])(?=.*[a-z])(?=.*[\\d])(?=.*[~!@#\\$%\\^&\\*])[\\w~!@#\\$%\\^&\\*]{8,}$"
같은 문자가 n번 연속되는 경우
. | 어떤 문자든지 한글자를 의미한다. |
() | 괄호 사이에 정규식 연산이 들어갈 수 있는데, 이 연산으로 매칭 된 값을 캡쳐한다. ([A-Z]+)는 알파벳 대문자 여러 글자와 매칭되고, ex) "APPLE" 전체 문자열과 매칭된다. ([A-Z])+는 알파벳 대문자 중 한글자가 여러번 반복되는 형태와 매칭된다. ex) "APPLE" 에서 "PP"와 매칭된다. |
\1 | 재참조 메타 문자 : 첫번째 그룹(괄호로 묶인 부분) 형태가 1번 반복된다. |
Swift에서 \
는 2번 사용해야함을 잊지 말자
이것들을 조합해보면??
"(.)\\1"
알파벳, 숫자, 특수문자 상관 없이 동일한 한글자가 2번 반복되는 형태를 찾을 수 있다.
더 많은 횟수로 반복하길 원한다면, \1
을 여러번 써준다.
"(.)\\1" // 2번 반복
"(.)\\1\\1" // 3번 반복
"(.)\\1\\1\\1" // 4번 반복
"(.)\\1\\1\\1\\1" // 5번 반복
모든 문자가 아닌, 특정 문자라면 괄호 안에 특정 문자를 넣어주면 된다.
'iOS_Swift' 카테고리의 다른 글
[iOS/Swift] iOS 앱 현지화 (한국어 앱 이름 변경까지!) - XCode Project Localization & CFBundleDisplayName (0) | 2021.05.31 |
---|---|
[Swift/iOS] 소셜로그인 - Facebook Login (0) | 2021.05.11 |
[iOS/Swift] XCode 프로젝트에 SwiftLint 적용하기 (0) | 2021.02.14 |
[iOS] 내 맥에 iPhone 연결하기 (iOS 개발/백업/Wi-Fi로 연결) (0) | 2021.02.12 |
[Swift] 구조체와 클래스 어떤 것을 선택해야 할까? (Apple 공식 Article) (0) | 2021.02.04 |