본문 바로가기
IT/개발

유니코드를 활용한 개발 일지

by GGT 2021. 7. 27.

유니코드라는 단어는 많이들 들어봤지만 실제로 어떻게 사용되고 있고 

어떤 존재인지 자세히 아는 경우는 드물다. (사실 내가 그랬다.)

 

현재 데이터를 다루는 일을 하고 있다보니까 문자열을 다루게 되는 경우가 많은데

이번에 내가 맞닥뜨린 경우는 바로 이모지 😀😀😀

 

사실 우리가 입력하는 모든 문자열들, 심지어는 널문자와 개행 문자들은 구분되기 위해

각자의 고유 번호가 존재하는데 이를 '유니코드'라고 한다.

 

이러한 유니코드는 과거에는 U+0000 ~ U+FFFF (앞에 U+를 접두로 유니코드임을 나타낸다)의 범위였지만

구분되어야하는 새로운 문자들이 등장함에 따라 현재는 U+10FFFF까지 존재하게 되었다.

(참고: https://unicode-table.com/en/blocks/)

 

U+0000 ~ U+FFFF의 범위는 BMP라고 불리며 2byte로 표현할 수 있는 범위지만

U+FFFF 이상의 범위는 supplementary Character라 불리며 표현에는 최대 4byte까지 필요하다.

 

이로 인해 개발에 몇 가지 문제가 생기는데

 

1. MySQL 문제

MySQL은 과거 UTF-8 encoding에 문자 별로 3byte까지만 할당했다.

왜냐면 그 당시에는 충분했으니까..

하지만 위에 나온대로 U+FFFF의 범위를 벗어나는 새로운 유니코드 문자들이 생겨나게 되고

그에 따라 해당 방식으로는 표현할 수 없는 문자들이 생겨나게 되었다.

 

그래서 현재는 많이 들어본 utf8bm4이라는 인코딩 방식을 지원하게 되었고

해당 인코딩은 4byte까지 할당하며 Supplementary Character를 커버할 수 있게 되었다.

 

2. JDK별 유니코드 처리 방식 문제

자바는 기본적으로 하나의 유니코드를 표현하기 위해

UTF-16방식으로 해당 값을 인코딩하여 Char (2byte)로 저장한다.

즉 '0'은 '\u0030'으로 표현한다.

 

허나 여기서 Supplementary Character는 경우가 달라지는데

U+FFFF(2byte, 12bits) 이상의 코드 포인트는 보다시피 UTF-16방식으로는 FFFF보다 큰 값을 표현할 수 없다!

 

따라서 유니코드 3.0부터는 BMP구역을 Supplementary Character를 위해 일부 할당하여

두 값의 조합으로 U+FFFF를 표현할 수 있게 지원한다!

 

따라서 해당 값들은 [High Surrogate] + [Low Surrogate]로 2개의 char type으로 표현할 수 있다.

 

하지만 여기서 문제는 JDK에 따라 이러한 Supplementary Character를 다루는 로직이 달라질 수 있다는 점인데

 

실제로 흔히 기업에서 사용하는 OpenJDK의 경우에는

위 유니코드의 Low Surrogate만을 regex로 찾아 부분적으로 치환하는 replaceAll() 메소드를 적용할 수 있지만

Oracle JDK에서는 해당 메소드가 동작하지 않는다.

 

+) 추가로 High Surrogate는 둘 다 동작하지 않는다.

 

다른 메소드도 같은 이슈가 있는지는 모르겠지만 이러한 작은 메소드 동작의 차이가

큰 시스템이나 모듈의 로직에 영향을 줄 수 있기 때문에 주의해야한다. (사실 나도 문제를 직접 겪고 나서야 알게 되었다.)

 

-----

 

아무래도 과거에 나왔단 라이브러리 혹은 시스템들은

유니코드의 BMP만 고려했기 때문에 이를 지원하지 않거나 예상치 못한 동작을 하는 경우가 많았는데

비교적 최근에 나온 Hive, Druid, Spark와 같은 빅데이터 시스템들은 이러한 문자들을 정상적으로 지원하는 것 같다.

 

 

-위 나온 모든 상황은 모두 내가 직접 겪으면서 몸으로 때운 이야기-

반응형

댓글