Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

일왓록(日What錄)

[Swift] 전화번호 "-" 자동 삽입되는 로직 구현하기 본문

iOS/Swift

[Swift] 전화번호 "-" 자동 삽입되는 로직 구현하기

일왓 2024. 1. 8. 17:17

개발을 하다보면 유저의 핸드폰 번호를 입력받을 일이 잦다.

그러다 보면 사용자가 "-"를 쓰지 않아도 자동으로 "-"를 넣는 로직을 구현하고 싶을 때가 많은데 이 로직을 처리하는 방법중 하나에 대해서 작성해볼까 한다.

 

⚠️알고리즘 적으로 흠이 많은 로직일 수도 있습니다. 검색을 통해 오신 분들은 참고 정도로 봐주시면 감사하겠습니다.

 


💡아이디어

  1. 사용자의 입력 발생
  2. 사용자의 입력 또는 이미 입력되어 있는(텍스트 필드에 존재하는) 값중 숫자만 filter
    1. 현재까지 입력된 텍스트 필드에 있는 값 또한 "-" 가 포함되어 있으므로 이를 제거 하여 숫자만 뽑아내는 작업이 필요함
  3. 사용자가 현재까지 입력한 값에 대한 배열 / 적용할 패턴에 대한 배열 / 패턴이 적용된 최종 출력 배열 생성
  4. 패턴 배열 앞자리부터 숫자가 들어갈 자리인지 확인하고 숫자가 들어갈 자리면 사용자 입력 배열에서 숫자를 넣고 배열 인덱스 증가
  5. "-"가 들어갈 자리이면  "-"를 넣고  패턴 배열의 다음 인덱스로 넘어감.
  6. 사용자가 입력한 값만큼 4~5번 반복

 

간단하게 생각하면 정해진 형식을 선언하고 형식에서 정해진 숫자 자리에 입력 값을 넣는 방식으로 구현하는 로직이다.

💻 코드

현재 String에서 숫자만을 filter하는 로직

extension String {
    
    var decimalFilteredString: String {
        get { return String(unicodeScalars.filter(CharacterSet.decimalDigits.contains))}
    }
    
}

현재 String에서 숫자만을 filter하는 코드를 연산 프로퍼티를 통해 뽑아낸다.

 

"-" 삽입 로직

"-" 삽입 전체 코드

func convertPhoneNumber() -> String {
        let input: [Character] = Array(self.decimalFilteredString)
        
        guard input.count > 3 else { return String(input) }
        
        //적용하고자 하는 패턴: 숫자가 들어갈 자리에 #(아무 값이나 상관은 없음)으로 설정해서 설정
        let defaultNumberPattern = "###-####-####"
        let oldNumberPattern = "###-###-####"
        
        let replacingSpace: Character = "#" //숫자가 들어갈 자리를 나타내는 비교 값
        
        // 이 코드는 010, 011과 같은 다른 형식을 대응하기 위한 코드
        let pattern: [Character] //패턴에 대한 배열
        
        switch input[2] {
        case "1":
            pattern = Array(oldNumberPattern)
        default:
            pattern = Array(defaultNumberPattern)
        }
        
        var formattedCharArray: [Character] = [] //패턴이 적용된 값이 들어갈 최종 결과 배열
        
        var inputIndex = 0 //사용자가 현재까지 입력한 값 배열의 인덱스
        var patternIndex = 0 //패턴 배열의 인덱스
        
        while inputIndex < input.count { //사용자 입력값 만큼 반복
            guard patternIndex < pattern.count else { return String(formattedCharArray)} //입력되는 값이 pattern보다 더 많을 수 있으니 확인 필요
            
            let inputChar = input[inputIndex]
            
            let patternChar = pattern[patternIndex]
            
            if patternChar != replacingSpace {
                formattedCharArray.append(patternChar)
            } else {
                formattedCharArray.append(inputChar)
                inputIndex += 1
            }
            
            patternIndex += 1
            
        }
        
        return String(formattedCharArray)
    }

필자는 

상세 설명

let input: [Character] = Array(self.decimalFilteredString)

 

텍스트 필드에 있는 (또는 입력한) 값을 숫자만 필터링한 String을 Character 배열에 담는다.

이 코드를 통해 사용자가 입력한, 또는 이미 입력되어 있는 "-" 문자를 제거한 순수 숫자들만 뽑아낼 수 있다.

 

//적용하고자 하는 패턴: 숫자가 들어갈 자리에 #(아무 값이나 상관은 없음)으로 설정해서 설정
let defaultNumberPattern = "###-####-####"

//각 문자별 배열을 생성
let pattern: [Character] = Array(defaultNumberPattern)

let replacingSpace: Character = "#" //숫자가 들어갈 자리를 찾을 비교 값

적용할 패턴을 스트링 형식으로 선언한 뒤, 배열을 만든다.

 

        var formattedCharArray: [Character] = [] //패턴이 적용된 값이 들어갈 최종 결과 배열
        
        var inputIndex = 0 //사용자가 현재까지 입력한 값 배열의 인덱스
        var patternIndex = 0 //패턴 배열의 인덱스
        
        while inputIndex < input.count { //사용자 입력값 만큼 반복
            guard patternIndex < pattern.count else { return String(formattedCharArray)} //입력되는 값이 pattern보다 더 많을 수 있으니 확인이 필요함 => 전화번호 자릿수를 넘었음에도 입력된 경우
            
            let inputChar = input[inputIndex] //입력 배열의 현재 index 문자
            
            let patternChar = pattern[patternIndex] //패턴 배열의 현재 index 문자
            
            if patternChar != replacingSpace { //패턴 배열 문자가 숫자 자리가 아니라면
                formattedCharArray.append(patternChar) //"-" 삽입
            } else { //패턴 배열 문자가 숫자 자리라면
                formattedCharArray.append(inputChar) //입력 문자를 넣고
                inputIndex += 1 //index + 1
            }
            
            patternIndex += 1 //패턴 배열 index 증가
            
        }

 

이부분이 사실상 핵심 로직이다.

일단 기본적으로는 입력된 값만큼 반복하되, 정해진 형식의 숫자 자리에 값을 넣는 방식이기 때문에 반복문 안에는 패턴 배열 index가 꾸준히 증가되는 방식이고 숫자 자리에 사용자 입력 숫자를 넣고 사용자 입력 값 배열 index를 증가 시키는 방식으로 로직을 구현하면 된다.

 

 

사용하는 법

필자는 위 코드를 모두 String의 Extension 안에서 구현했기에 String의 메서드를 실행시키는 방식으로 구현했고, Rx를 사용했기 때문에, 사용하는 쪽은 이런 방식으로 구현했다.

input.inputPhoneNumber
            .subscribe(with: self) { owner, phoneNumber in
                patternedNumber.accept(phoneNumber.convertPhoneNumber())
            }
            .disposed(by: disposeBag)

이런 방식으로 구현 했지만 일반적으로는 textField에 addTarget을 통해 @objc func 안에서 <전화번호String>.convertPhoneNumber 메서드를 불러주는 방식으로 구현해주면 된다.

 

📱 구현 결과