[Swift] String 타입에 length 메소드가 없는 이유

Swift의 String 타입에는 length 프로퍼티나 메소드가 없다. 이상하게 들리겠지만 실제로 그렇다. Swift에서 문자열의 길이를 구하려면 이럼 메소드 대신에 countElements(_:)라는 글로벌 함수를 사용해야 한다.

더군다나 이 countElements(_:) 함수는 문자열을 처음부터 순회(iterate)하기 때문에 매우 긴 문자열을 다룰 때라면 주의해야 한다. NSStringlength 프로퍼티를 제공하는데 왜 Swift의 문자열 타입은 길이 프로퍼티를 갖지 않을까?

NSString은 내부적으로 유니코드 문자열(정확히는 일련의 코드값)을 UTF16 형식으로 인코딩한 값을 갖는다. UTF16에서는 각 유니코드 스칼라값은 16비트 크기의 값으로 변환된다. 여기서 주의할 것은 “한 개의 유니코드 문자”가 아닌 “한 개의 유니코드 값”이라는 점인데, 유니코드는 하나의 값이 다른 값과 조합되어 문자로 표기되는 경우가 종종 있기 때문이다. 이를 테면 U+301은 영문자 모음에 붙는 첨자인데, “café”를 표현할 때 e와 결합한다. 즉

var word = "cafe"
word += "\u{301}"
println(word)
//  café

이렇게 된다. 앞서 언급한 countElements() 함수는 이 때 é를 한 개 글자로 계산한다. 하지만 이 문자열을 표현할 때 사용된 실제 유니코드값은 5개이다. 이는 유니코드 문자열은 표현방식에 따라서 사용되는 메모리의 크기가 달라질 수 있다는 점이다. 따라서 불가피하게 조합가능한 유니코드 값들을 찾기 위해서는 문자열 내부를 순회하는 작업이 필요하고, 단순한 프로퍼티로는 이를 제공하지 않는다.

println(countElements(word))
//  4

반대로 NSString의 길이는 사용된 유니코드값들이 16비트 단위로 저장되므로 “문자열의 길이”가 곧 사용된 정보의 개수와 같다. 따라서 “몇 자”가 아닌 “몇 개의 유니코드 값”의 의미가 된다.

println(NSString(format:"%s", word).length)
//  5

물론, Swift 문자열이 NSString의 length 프로퍼티와 같은 값을 구하고자 한다면 utf16Count라는 프로퍼티를 사용하면 된다.

println(word.utf16Count)
//  5

끗.