태그 보관물: UnicodeScalarView

UnicodeScalar

UnicodeScalar

유니코드 문자 1개에 해당하는 코드 포인트값을 담고 있는 데이터이다. UnicodeScalar는 4바이트 유니코드 값 1개에 대응되기 때문에 UInt32 타입으로 변환하거나, UInt32값으로부터 생성해낼 수 있다.

let i:Uint32 = 0xac01
let c = UnicodeScalar(i)
print(c)
let v:UInt32 = c.value

Swift의 Character 타입은 글자 1개를 나타내는 자료형이지만, 유니코드 문자 중에서는 여러 개의 코드 값이 하나로 합쳐진 글자들이 있기 때문에 1개의 Character 타입 값은 1개 혹은 그 이상의 UnicodeScalar 값으로 표현된다.

예를 들어 한글 "학"은 1개의 글자로 그 자체로 유니코드 코드포인트 값 1개에 대응될 수도 있지만, 한글자모 "ㅎ" + "ㅏ" + "ㄱ"의 조합일 수도 있다. 이 경우에는 코드 포인트값은 3개이지만, 글자로는 1개로 취급된다.

예를 들어 한글 “학”의 경우를 보자.

let a = "학"
let c = a.unicodeScalars[a.unicodeScalars.startIndex].value
print(String(format:"0x%x", c)) 
// 0xd559 (45617)

print("학 ==> 학")
print("글자 수: \(a.characters.count)") // 1
print("코드 수: \(a.unicodeScalars.count)") // 
print("\n")

"학"의 유니코드 코드포인트 값은 45617로 하나의 코드로 된 문자이다. 그리고 당연히 1개의 글자로 되어 있다. 이를 유니코드의 초중종성 분리를 통해 각각의 자모로 분리해보자.

//  각각의 자모 인덱스로 분리
let x = (c - 0xac00) / 28 / 21
let y = ((c - 0xac00) / 28) % 21
let z = (c - 0xac00) % 28

//  각각의 자모 인덱스로부터 자모 코드값 생성
let i = UnicodeScalar(0x1100 + x) // 0x1100 -> 초성 'ㄱ'
let j = UnicodeScalar(0x1161 + y) // 0x1161 -> 중성 'ㅏ'
let k = UnicodeScalar(0x11a6 + 1 + z) // 0x11A6 -> 종성 {받침없음}

print("분해된 자모: \(i), \(j), \(k)") 
//  분해된 자모: ㅎ, ㅏ, ㄱ

이 때 분해된 각 자모의 값은 0x1112, 0x1161, 0x11A8이 된다. 이 자모코드값을 이용해서 문자열 "학"은 다음과 같이 쓸 수 있다.

let compositedString = "\u{1112}\u{1161}\u{11A8}"
print("자모코드를 합성한 문자열: \(compositedString)")
//  학

이 세 개의 자모 코드는 하나의 문자를 표시하도록 조합되기 때문에, 표현상 한 글자 짜리 문자열이 된다.

print("ㅎㅏㄱ ==> 학")
print("글자 수: \(compositedString.characters.count)") // 1
print("코드 수: \(compositedString.unicodeScalars.count)") // 3

하지만 글자 수는 1개이지만 학(0xD559)와 달리 3개의 코드포인트로 저장되어 있고 표시하는 글자는 같다. 그리고 이 두 개는 문자열로 표현되는 경우 내부에 저장된 데이터는 각각 다르지만

print(a == compositedString)
//  true

동일한 값으로 간주된다.

다루는 방법

문자열 타입에서 .unicodeScalars 프로퍼티를 이용해서 해당 문자열의 유니코드 코드 포인트뷰를 얻을 수 있다. 이는 UnicodeScalarView 타입으로, Slicable, SequenceType, ExtensibleCollectionType, RangeReplaceableColloectionType 등의 프로토콜을 따르고 있어서 배열과 유사하게 서브스크립팅을 하거나 append, insert, remove등의 조작을 통해 manipulate할 수 있다.

또한 앞서 언급한 바와 같이 내부적으로 하나의 코드 포인트는 UInt32 타입의 정수값으로 취급되므로, 유니코드 스칼라 타입을 이용하여 유니코드 코드값을 문자로 변환하는 것도 가능하다.