GGURUPiOS

[Swift] 왜 Swift 에는 String을 subscript 를 정수형으로 접근할 수 없을까? 본문

Swift/문법 파헤치기

[Swift] 왜 Swift 에는 String을 subscript 를 정수형으로 접근할 수 없을까?

꾸럽 2023. 11. 3. 17:39

안녕하세요

이번시간에는 String 타입에는 왜 정수형으로 접근할 수 없는지를 알아보도록 하겠습니다

 


우리는 Array나 Dictionary같은 자료구조에 접근할 때, Subscripts 를 통해 간단히 접근할 수 있었습니다.

예를 들어 아래와 같은 코드가 그 예시입니다.

let intArray: [Int] = [1, 2, 3, 4, 5]
let someDictionary: [String: String] = [
    "민수": "25살",
    "철수": "28살"
]

print(intArray[0]) // 1 출력
print(someDictionary["민수"]!) // 25살 출력

 

그럼 String에도 마찬가지로 정수형으로 접근할 수 있을까요?

 

String에서는 Int형으로는 서브스크립트에 접근할 수 없고, String.Index를 사용하라고 하네요.

사용법은 아래에서 다뤄보고, 안되는 이유에 대해 알아보도록 하겠습니다.

 

문자열은 어떻게 구성되어 있을까?

기본적으로 String은 독립적인 유니코드 문자로 구성되며, 다양한 유니코드 표현으로 해당 문자에 접근할 수 있도록 지원한다고 합니다.

 

유니코드가 뭘까요?

다양한 문자 체계에서 텍스트를 인코딩, 표현, 및 처리하기 위한 국제 표준입니다.

유니코드를 사용하면 모든 언어의 거의 모든 문자를 표현할 수 있습니다

 

유니코드 스칼라 값

스위프트의 String 은 유니코드 스칼라 값으로 설계되어 있습니다. 유니코드 스칼라 값은 고유한 21비트 숫자입니다.

예를 들어

  라틴어 "a"의 값은 U+0061 입니다.이 이모지의 경움ㄹㄴㅇ

 

모든 21비트 유니코드 스칼라 값이 문자에 할당되는 것은 아니며, 일부 스칼라 값은 나중에 할당하거나

UTF-16 인코딩에 사용하기 위해 예약되어 있다고 한다.

 

Extended grapheme clusters (확장된 그래프 클러스터)

스위프트의 모든 Character 타입 인스턴스는 하나의 확장 그래프 클러스터를 나타낸다고 합니다.

확장 그래프 클래스터는 하나 이상의 유니코드 스칼라로 구성된 시퀀스로, 사람이 읽을 수 있는 단일 문자를 생성한다고 합니다.

 

무슨 말일까요?

결국 유니코드 스칼라 값 하나로 이루어진 것이 아니라, 결합해서 사용할 수 있다는 말입니다

예를들어 보겠습니다 

 

let precomposed: Character = "\u{D55C}"                  // 한
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}"   // ᄒ, ᅡ, ᆫ
// precomposed is 한, decomposed is 한

 

만약 두 상수를 == 연산자로 비교를 한다면 결괏값은 무엇일까요?

답은 true 입니다.

문자열에서 동등의 의미는 언어적 의미와 모양이 동일하면, 다른 유니코드 스칼라로 구성되어 있어도 동등한 것으로 간주 됩니다.

 

 

Counting Characters

서브스크립트는 일단 제쳐두고, 

문자열에서 Character의 갯수를 어떻게 파악할까요?

String에는 count라는 프로퍼티를 내장하고 있습니다.

 

아래의 예제를 보고 추측해봅시다.

var word = "cafe"
print("the number of characters in \(word) is \(word.count)")
// Prints "the number of characters in cafe is 4"


word += "\u{301}"    // COMBINING ACUTE ACCENT, U+0301


print("the number of characters in \(word) is \(word.count)")
// Prints "the number of characters in café is 4

 

"cafe" 라는 문자열에, 유니코드 스칼라를 결합해서 네번째 글자를 e에서 로 변경했습니다.

그럼에도 count는 여전히 4로 출력됩니다.

 

무엇을 의미할까요?

 

확장 그래프 클러스터는 서로 다른 문자 또는 같은 문자의 서로 다른 표현은, 저장하는 데 있어서

서로 다른 양의 메모리를 필요로 한다는 것을 뜻합니다.('한' 을 '한', ㅎ ㅏ ㄴ 으로 표현 가능)

 

따라서 문자열을 반복하면서 확장된 그래프 클러스터의 경계를 결정해야 하고, 문자열의 문자 수를 계산해야 합니다.

이는 긴 문자열에서 count 속성전체 문자열을 반복해야하기 때문에 비용이 많이 발생하므로 유의 해야합니다!

 


결국 String의 Subscript 정수형으로 접근할 수 없는 이유는?

위의 글을 다 읽고 오셨다면, 대략적인 이유를 파악할 수 있습니다.

결국 String은 문자에 따라 저장하는 데 필요한 메모리의 양이 다를 수 있으므로 특정 위치에 있는 문자를 확인하려면

해당 문자열의 시작 또는 끝에서 각 유니코드 스칼라를 반복해야 합니다.(스칼라 값들의 경계를 파악해야하므로)

이러한 이유로 정수 값 인덱싱이 안됩니다. (이러한 이유로 막아놓은 것 같습니다.(근데 왜 count는 되게 해놓은거지..?))

 

그렇다면 String의 n번째 문자에 액세스하려면 어떻게 해야할까요?

String.Index 타입을 사용해 접근할 수 있습니다.

 

아래의 예시처럼 접근이 가능합니다.

let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// a

 

물론 범위를 벗어나면 런타임 에러를 발생시킵니다.


출처

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/stringsandcharacters/#Unicode-Scalar-Values

 

Documentation

 

docs.swift.org