[Swift] String은 Subscript로 접근이 안되는 이유

Updated:

String의 요소는 Int형을 파라미터로 사용해 subscript로 접근이 안되는 이유

  • Collection 타입인 ArrayInt형 index를 파라미터로 넘겨주어 subscript를 통해 해당 요소에 접근할 수 있지만,
    let number: [Int] = [1, 2, 3, 4, 5]
    number[1]  // 2
    
  • StringString.Index 구조체를 파라미터로 넘겨주어 subscript를 통해 해당 요소에 접근해야 한다.
    let str: String = "123456"
    let index = str.index(str.startIndex, offsetBy: 1)
    str[index] // "2"
    str[1] // error
    

Swift의 문자는 유니코드를 준수하여 표기된다

  • 유니코드 문자는 크기가 가변적이기 때문에 하나의 문자가 하나의 바이트보다 클 수 있다.
  • 하나의 문자가 하나이상의 바이트를 차지할 수 있기때문에, 일반적인 문자열 배열처럼(다른 언어의 문자열 배열처럼) 1 바이트 단위인 인덱스로 특정 문자에 접근할 수가 없다.
  • 유니코드 표현방식으로는 utf8(8bit), utf16(16bit), utf32(32bit)가 존재하며 Swift에서는 Unicode Scalar(21bit)가 존재한다.

*유니코드: 존재하는 모든 문자를 모든 플랫폼에 일관되게 표현하고 다룰 수 있도록 설계된 산업 표준 문자코드이다

Swift 의 String, Character 타입은 Unicode Scalar 값으로 이루어져 있다.

  • Character 타입은 하나이상의 Unicode Scalar 값으로 구성되어 있다.
    let character1: Character = "\u{D55C}"                  // '한'
    let character2: Character = "\u{1112}\u{1161}\u{11AB}"   // 'ᄒ, ᅡ, ᆫ' == '한'
    
  • String 타입은 하나이상의 Character 타입(or Unicode Scalar들)으로 구성되어 있다.
    let character2: Character = "\u{1112}\u{1161}\u{11AB}"   // 'ᄒ, ᅡ, ᆫ' == '한'
    let str1 = "\u{1112}\u{1161}\u{11AB}국" // "한국"
    let str2 = "\(character2)국"            // "한국"
    let str3 = "한국"                        // "한국"
    

Stringsubscript를 통해 요소에 접근할때 순차적으로 순회한다.

  • 일반적인 CollectionType(Array 등) 은 RandomAccessCollection 프로토콜을 채택하고 있어 O(1) 의 시간복잡도로 요소에 접근한다.
    let number = [1, 2, 3, 4, 5]
    number[1] // 2
    
  • StringBidirectionalCollection 프로토콜을 채택하여 순차적으로 요소를 조회하면서 타겟 요소까지 접근하여 구성하고 있는 Unicode Scalar 값의 갯수에 상응하는 O(n)의 시간복잡도가 소요된다.
    • String 을 이루는 Character(or Unicode Scalar들)의 Unicode Scalar 값 갯수가 다를 수 있기 때문에 순차적으로 Unicode Scalar 요소들을 하나하나 순회하여 하나의 문자(ex. "\u{1112}\u{1161}\u{11AB}" // "한" )를 찾는다.

String의 요소를 Int형 파라미터를 사용해 subscript로 접근할 수 있는 방법

extension String {
    subscript(idx: Int) -> String? {
        guard (0..<count).contains(idx) else {
            return nil
        }
        let target = index(startIndex, offsetBy: idx)
        return String(self[target])
    }
}

let str = "ronick"
str[2] // "n"
str[7] // nil

📝 참고 사이트

Categories:

Updated:

Leave a comment