728x90
반응형
2021 KAKAO BLIND RECRUITMENT 1번 문제인 신규 아이디 추천.
python으로는 정규표현식을 작성하는게 조금 익숙하다고 느꼈는데, Swift로 하려니 또 색다른 느낌.
Swift로도 정규표현식을 제대로 공부해야할 필요가 있다고 생각된다. 다른 코테에서도 항상 문자열을 다루는 문제는 꼭 나오는 것 같다!
문제를 읽어봤을 때, 그냥 차례차례 구현하면 되겠다라는 생각이 들었다. 다만 생각과 내 손은 항상 같지 않다는 거...
아무튼 문제에 나와있는 것 처럼 스텝을 나누어 진행했다.
import Foundation
func solution(_ new_id:String) -> String {
// 소문자 치환은 먼저 진행
var id = new_id.lowercased()
// 각 단계별 수행
id = step7(step6(step5(step4(step3(step2(id))))))
return id
}
func step2(_ id: String) -> String {
// 숫자,문자,특정 특수문자를 제외하여 선별
// ** 원소를 하나하나 꺼냈기에 마지막에 joined()로 연결
let special = ["-","_","."]
return id.filter {$0.isNumber || $0.isLetter || special.contains(String($0))}.map {String($0)}.joined()
}
func step3(_ id: String) -> String {
var res = id
// .을 2개 이상 포함시 .으로 수정 (계속 반복)
while res.contains("..") {
res = res.replacingOccurrences(of: "..", with: ".")
}
return res
}
func step4(_ id: String) -> String {
var newid = id
// index를 구해서 접근해도 되나 빠르게 first / last로 접근!
if newid.first == "." {
newid.removeFirst()
} else if newid.last == "." {
newid.removeLast()
}
return newid
}
func step5(_ id: String) -> String {
var newid = id
// 비어있을 경우 대처
if newid.isEmpty {
newid += "a"
}
return newid
}
func step6(_ id: String) -> String {
var newid = id
// 16자리 이상일 경우, 15자리까지만 출력
// newid.prefix(15) 만으로도 추출 가능
if newid.count >= 16 {
let start = newid.index(newid.startIndex, offsetBy:0)
let end = newid.index(newid.startIndex, offsetBy:14)
let rnge = start...end
newid = String(newid[rnge])
}
return step4(newid)
}
func step7(_ id: String) -> String {
var newid = id
// 길이가 2이하일 경우 계속해서 마지막 원소 추가
while newid.count < 3 {
guard let last = newid.last else {return ""}
newid += String(last)
}
return newid
}
Step별로 풀이하다보니 별다른 프로세스를 적는 것 보다는 정규표현식을 한 번 정리하는게 좋을 것 같다.
[ Swift 정규표현식 ]
사실 위 문제는 정규표현식으로 풀이되지는 않았다. 다만 앞으로 더 복잡한 문자열을 다루게 될 경우를 대비해서 알아두자.
Swift regex를 찾아봤을 때 가장 무난하게 사용되는 방법은 아래와 같다.
// 0. 문자열
let id = "chamin!@#95"
// 1. 문자 패턴 정의
let pattern = "[A-Za-z0-9]"
// 2. 정규표현식내 문자열 적용
let regex = NSRegularExpression(pattern: pattern, options:[])
// 3. 정규표현식을 활용한 문자열 탐색 (.firstMatch)
let range = NSRange(location: 0, length: id.count)
if let v = regex.firstMatch(in: id, options:[],range : range) {
// 존재할 경우 실행할 부분
} else {
// 찾고자 하는 값이 없을 경우 실행할 부분
}
위 사용법을 기본으로 하고 여러 패턴들을 숙지하여 응용하면 된다!
기본 문자, 숫자 지정 ( [ ]안에 넣어서 그룹으로 만들어 사용하자 )
- [A-Z] : 대문자
- [a-z] : 소문자
- [0-9] : 숫자
- \w : 문자
- \d : 숫자
- \s : 띄어쓰기 공간
부정의 의미 ( ~ 빼고 다 )
- [^A-Z] : 대문자 빼고 다
- [^0-9] : 숫자 빼고 다
동일한 문자가 연속으로 있는지 확인하고 싶을 경우
- (.) : 모든 문자
- (.)\\1{3,} : 앞과 동일한 문자가 4개 이상 이어지는 경우 ( ex. aaaa )
문자열 내에 특정한 문자의 등장 횟수가 n번 이상인지 판단하는 방법
- 먼저 문자열을 정렬! (sort나 sorted 사용)
- (.)\\1{n,} : n개 만큼 탐지하여 판단한다.
etc
- ab|cd : ab나 cd 탐지!
- ^ : 시작
- $ : 끝
더 자세한건 아래 Cheat Sheet 참고~!
(참고용)
Cheat Sheet
Character classesAnchorsEscaped charactersGroups & LookaroundQuantifiers & Alternation
. | any character except newline |
\w \d \s | word, digit, whitespace |
\W \D \S | not word, digit, whitespace |
[abc] | any of a, b, or c |
[^abc] | not a, b, or c |
[a-g] | character between a & g |
^abc$ | start / end of the string |
\b | word boundary |
\. \* \\ | escaped special characters |
\t \n \r | tab, linefeed, carriage return |
\u00A9 | unicode escaped © |
(abc) | capture group |
\1 | backreference to group #1 |
(?:abc) | non-capturing group |
(?=abc) | positive lookahead |
(?!abc) | negative lookahead |
a* a+ a? | 0 or more, 1 or more, 0 or 1 |
a{5} a{2,} | exactly five, two or more |
a{1,3} | between one & three |
a+? a{2,}? | match as few as possible |
ab|cd | match ab or cd |
728x90
반응형