99클럽 코테 스터디 1일차 TIL + Swift String Index에 왜 Int로 접근하면 안돼????

피터·2025년 3월 31일
0

✅ 오늘의 학습 키워드

  • Swift 문자열 인덱스 (String.Index)
  • 유니코드와 문자열 처리 방식
  • 코딩테스트 대비 문자열 탐색 및 조작 방법
  • Swift에서 문자열을 다루는 올바른 방법

1. 99클럽 코테 스터디 시작 & 첫 문제

오늘부터 99클럽 코테 스터디를 시작해서 매일 코딩테스트 문제를 풀기로 했다. 첫 번째 문제는 명령 프롬프트였다.

하지만 시작부터 삽질이 시작되었다.

문제를 풀기 전에 "String은 Character의 배열이니까 Subscription을 Int로 접근 가능하겠지?" 라고 생각했는데, 이게 큰 오산이었다. Swift의 String은 배열과 다르게 Int 인덱스로 접근할 수 없었다. 왜 그런 걸까?

2. Swift에서 String의 인덱스가 Int가 아닌 이유

Swift의 String은 유니코드(Unicode) 기반으로 동작하기 때문이다.

🔹 유니코드 기반이란?

우리가 보기에 "가나다"는 각각 하나의 글자로 보이지만, 컴퓨터 내부에서는 코드의 나열로 저장된다. 예를 들어:

  • "가"는 하나의 코드 단위일 것 같지만, 실제로는 여러 바이트로 구성될 수 있다.
  • "🤔" 같은 이모지도 마찬가지다.

즉, 단순히 Int 인덱스를 사용하면 문자 경계를 정확히 알 수 없기 때문에 잘못된 문자 데이터를 읽을 가능성이 생긴다. 따라서 Swift는 정확한 문자 단위를 보장하는 String.Index 타입을 제공한다.

3. 올바른 접근 방법: String.Index 사용하기

문자열에 접근하려면 String.Index를 사용해야 한다.

let text = "Hello, Swift!"
let index = text.index(text.startIndex, offsetBy: 7)
print(text[index]) // "S"

이 방식은 문자열의 시작 위치(startIndex)에서 정확한 문자 단위로 이동하는 방식이기 때문에 안전하다.

4. 배열처럼 접근하고 싶다면?

만약 Int 인덱스를 쓰고 싶다면, 문자열을 배열로 변환하면 된다.

let characters = Array(text)
print(characters[7]) // "S"

하지만, 이 방식은 문자열 전체를 새로운 배열로 변환하는 과정이 필요하므로 성능을 고려해야 한다.


📝 오늘의 회고

❓ 어떤 문제가 있었고, 나는 어떤 시도를 했는지?

  • text[0]처럼 배열처럼 접근하려다가 컴파일 에러가 발생했다.
  • String이 Collection을 준수하니까 당연히 Int 인덱스로 접근할 수 있을 거라고 생각했는데, 그렇지 않았다.

초기 문제 풀이:

if let count = Int(readLine() ?? "0") {
    var inputs: [String] = []
    for _ in 0..<count {
        if let line = readLine() {
            inputs.append(line)
        }
    }
    
    func makeCommandPrompt(count: Int, _ values: [String]) -> String {
        var result = String()
        let length = values.first?.count ?? 0
    
        for index in 0..<length {
            var currentChar = String()
            for value in values {
                guard index < value.count else { continue }
                let currentIndex = value.index(value.startIndex, offsetBy: index)
                let char = value[currentIndex]
                if currentChar.isEmpty {
                    currentChar.append(char)
                }
                if currentChar != String(char) {
                    currentChar = "?"
                }
            }
            result.insert(contentsOf: currentChar, at: String.Index(utf16Offset: index, in: values.first ?? ""))
            currentChar = String()
        }
    
        return result
    }
    
    makeCommandPrompt(count: count, inputs)
}

🔍 어떻게 해결했는지?

  • String.Index를 활용하여 문제를 다시 접근했다.
  • indices를 사용하여 각 문자를 비교하는 방식으로 수정했다.

최종 해결 방법:

let count = Int(readLine() ?? "0") ?? 0
var inputs: [String] = []
for _ in 0..<count {
    if let line = readLine() {
        inputs.append(line)
    }
}

func makeCommandPrompt(count: Int, _ values: [String]) -> String {
    return values[0].indices.map { index in
        let isSame = values.allSatisfy { $0[index] == values[0][index] }
        return isSame ? String(values[0][index]) : "?"
    }.joined()
}

print(makeCommandPrompt(count: count, inputs))

🌟 무엇을 새롭게 알았는지?

  • Swift의 String은 유니코드 안전성을 보장하기 위해 Int 인덱스 접근을 막아놓았다는 사실.
  • String.Index를 활용하는 방법을 익혔다.
  • allSatisfy를 사용하여 문자열 비교를 간결하게 할 수 있음을 알게 되었다.
profile
iOS 개발자입니다.

0개의 댓글