👨🏻‍💻iOS 공부/Swift_알고리즘 풀이

[프로그래머스] 신규 아이디 추천 (feat. Swift 정규표현식)

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
반응형