001.1 유니코드 문자는 어떻게 처리할까?
개발자는 아스키(ASCII) 문자에 굉장히 익숙하다. 0부터 31까지는 출력할 수 없는 제어 코드고 32부터 127까지는 출력할 수 있는 문자, 128부터 255까지는 확장 아스키 코드다. 하지만 유니코드 문자는 어떨까? 유니코드 문자를 조작해야 하는 문제가 나오면 이 절을 떠올리자.
간단히 말해 초기 유니코드 버전은 65,535(0xFFFF)보다 작은 값의 문자를 포함했다. 자바는 이러한 문자를 16비트 char 데이터 타입으로 표현한다. charAt(i)를 호출하면 i가 65,535를 초과하지 않는 한 올바르게 동작한다. 하지만 시간이 흐르며 유니코드에 문자가 추가됐고 최댓값도 1,114,111(0x10FFFF)까지 늘어났다. 이러한 문자들은 16비트로 표현할 수 없으므로 (코드 포인트(code point)라 불리는) 32비트 값을 UTF-32 인코딩 스키마에 고려하게 되었다.
안타깝게도 자바는 UTF-32를 지원하지 않는다! 그래도 유니코드는 16비트만으로 이러한 문자를 표현할 방법을 고안해냈다. 바로 다음과 같은 방법이다.
• 16비트 상위 대리(high surrogate): 값 1,024개(U+D800부터 U+DBFF까지)
• 16비트 하위 대리(low surrogate): 값 1,024개(U+DC00부터 U+DFFF까지)
상위 대리와 하위 대리로 하나의 대리 쌍(surrogate pair)을 정의한다. 대리 쌍은 65,536(0x10000)에서 1,114,111(0x10FFFF) 사이의 값을 표현하는 데 쓰인다. 즉, 하나의 코드 포인트1로 병합되는 유니코드 대리 쌍(문자(기호) 하나가 문자 쌍에 대응한다)으로 유니코드 추가 문자라 불리는 특정 문자들을 표현한다. 자바는 대리 쌍 표현을 활용해 codePointAt(), codePoints(), codePointCount(), offsetByCodePoints() 같은 메서드 집합으로 코드 포인트를 노출한다(자세한 내용은 자바 설명서를 참고한다). charAt() 대신 codePointAt()을, chars() 대신 codePoints()를 호출하면 아스키 외에 유니코드 문자까지 처리하도록 해법을 작성할 수 있다.
1 역주 유니코드 문자 집합에서 각 문자의 위치를 코드 포인트로 표현합니다.