String in Swift

Swift의 문자열

수정 (2015. 12. 07) : Swift2.0에서부터 문자열은 더 이상 Collection 타입이 아니므로 [Character] 타입으로 변경할 수 없으며, advance() 함수 역시 전역 함수에서 제거되고 Index 타입의 메소드로 변경되었다. NSString은 유니코드 문자열을 UTF16으로 인코딩한 바이트배열로 문자를 다루는데 비해, Swift의 문자열은 유니코드 문자열의 복잡 다단한 특성들을 정확히 반영하기 위해 애써서 디자인한 흔적들이 눈에 띈다. 보다 자세한 내용에 대해서는 따로 포스팅하겠다.

Swift의 문자열은 유니코드 문자열이고, 유니코드의어떤 특징들(여러개의 스칼라 코드가 하나의 문자로 결합하는 등)로 인해서 내부적으로는 단순 배열이 아니다. 따라서 Swift의 문자열은 인덱스에 의한 랜덤액세스를 지원하지 않는다. 즉, NSStringcharacterAtIndex:와 동일한 메소드를 지원하지 않는다. 컨셉상, Swift의 문자열은 배열보다는 양방향 리스트에 더 까운 구조이다.

문자열 내 개별문자(Character)와 범위의 인덱스들은 String.Index라는 불투명 타입에 의해 구현되며, 이 타입은 BidirectionalIndex라는 프로토콜 타입이다. 따라서 특정 위치의 문자를 얻기 위해서는 먼저 해당 문자열에 startIndex 값을 물어본 다음, 표준 함수인 —advance()를 사용하여 해당 위치 인덱스로 순차적으로 이동하고– 이 시작 인덱스의 advancedBy() 메소드를 이용해서 해당 위치로부터 원하는 만큼의 오프셋을 준 인덱스를 구한 후, 이 인덱스를 이용한 subscription으로 특정 위치의 문자를 구할 수 있다. (참 어렵게도 해놨다)

let digits = "0123456789"
let position = 3
let index = digits.startIndex.advancedBy(position)
let character = digits[index]

이를 이용하면 문자열의 뒤에서부터 접근하는 경우에

let index2 = digits.endIndex.advancedBy( -1 * position)
let character2 = digits[index2]

이런 식으로 advance() 함수의 두 번째 인자에 음수값을 주어 뒤에서부터 세어 나갈 수 있다.

메모리를 좀 더 많이 쓰는 대신 타이핑의 수고로움을 더는 방법으로는 문자열을 배열로 캐스팅하면 Character의 배열을 얻게 된다는 점을 착안하여,

let character3 = Array(digits)[4]

라고 쓰는 방법도 있긴하다.

Swift 2.0에서 문자열은 더 이상 집합 타입이 아니며, 따라서 [Characters] 타입으로 변환되지 않는다. 이는 문자열의 개수를 세는 countElement() 등의 함수의 비효율성을 극복하기 위해서, 단일 문자열이 여러 가지 타입으로 인코딩된 데이터 맵을 가지는 형태로 변환되었다.

좀 더 세련된 방법으로 문자열을 정수 인덱스를 지원하도록 서브스크립트를 확장하는 방법이 있다.

extension String {
    subscript(integerIndex: Int) -> Character {
        if integerIndex >= 0 {
            let index = startIndex.advancedBy(integerRange.startIndex)
            return self[index]
        }

    }

    subscript(integerRange: Range<Int>) -> String {
        let start = startIndex.advancedBy(integerRange.startIndex)
        let end = startIndexBy(integerRange.endIndex)
        let range = start..<end
        return self[range]
    }
}

위 서브스크립트에서 정수 인덱스가 음수인 경우, 파이썬과 비슷하게 뒤쪽에서부터 문자를 출력하도록 하는 것도 가능할 것이다.