Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blog: 05-14-kadio #58

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions blog/2023/05-14-kadio/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
authors: kadio
slug: unicode-processing
---
# 유니코드 문자열을 Hex Code 수준에서 처리하기

안녕하세요! 20년과 23년도에 SPARCS의 개발자로 활동 중인 장준하(kadio)입니다.

저는 초당 수천만~억 단위의 문자 처리가 가능한 대규모 프로젝트를 진행하면서 속도 개선을 위해 C/C++ 언어를 사용했었는데, C/C++ 언어는 문자열과 인코딩 처리에 관한 라이브러리와 함수들이 다소 불완전하여 유니코드 문자열을 Hex Code 수준에서 처리해야 했습니다.

이 글에서는 겪었던 유니코드 관련 문제와 그 해결 과정을 소개하려 합니다.

## 유니코드

유니코드(Unicode)는 컴퓨터에서 전 세계의 모든 문자를 표현하고 다룰 수 있도록 설계된 산업 표준입니다.

과거에는 나라별로 문자를 표현하기 위해 자체적으로 인코딩 방식을 개발해 사용했습니다. 이에 따라 서로 다른 국가와 언어를 다루기 어렵고, 호환성 문제가 발생하는 등의 문제가 있었습니다. 이를 해결하기 위해 유니코드가 제정되어, 전 세계의 모든 문자를 일관되게 표현하고 다룰 수 있도록 표준을 제공하고 있습니다.

유니코드의 주요 목적은 기존의 문자 인코딩 방식들을 모두 유니코드로 교체하여 서로 호환성을 지원하게 함으로써, 국제적인 정보 공유에서의 장애 요인을 없애는 것입니다. 또한, 유니코드가 다양한 문자 집합들을 통합하는 데 성공하면서, 컴퓨터 소프트웨어의 국제화와 지역화에도 큰 도움을 준 것으로 평가받고 있습니다.

## UTF-8

유니코드를 위한 가변 길이 문자 인코딩 방식 중 하나인 UTF-8은, 켄 톰프슨과 롭 파이크가 개발한 알고리즘입니다. 이름인 "UTF-8"은 Universal Coded Character Set + Transformation Format – 8-bit의 약자로, 원래는 FSS-UTF(File System Safe UCS/Unicode Transformation Format)라는 이름으로 제안되었습니다.

UTF-8은 1byte에서 4byte까지 다양한 크기의 byte를 사용하여 유니코드 문자를 표현합니다. ASCII 문자들은 1byte만으로 표현할 수 있고, 그 이후의 문자들은 byte 크기가 정해져 있지 않아 해당 문자의 유니코드 코드 포인트에 따라 byte 크기가 결정됩니다.

UTF-8 인코딩의 장점은 유니코드 문자들을 빠르고 효율적으로 저장할 수 있다는 점입니다. 또한, 과거의 다른 인코딩 방식과 호환성이 뛰어난 것으로, 기존의 코드를 수정하지 않고도 UTF-8을 적용할 수 있는 경우도 있습니다. 최근에는 UTF-8 인코딩이 인터넷에서 가장 많이 사용되는 문자 인코딩 방식 중 하나로 자리 잡았습니다.

## Windows 10 / UTF-8 설정법

윈도우를 사용하시는 분들이라면 명령 프롬프트에서 한글이 깨지는 현상을 겪어보셨을 수도 있는데, 이는 언어 설정이 한글로 된 OS에서는 CMD Codepage의 기본값이 949이기 때문입니다. (UTF-8의 CMD Codepage는 65001)

명령 프롬프트에 `chcp 65001`을 입력하여 임시로 인코딩 방식을 UTF-8로 설정할 수 있고, C++ 언어로 해당 부분을 구현하면 아래 코드와 같습니다.

```c++
// Set UTF-8 Code Page Identifiers
system("chcp 65001");
```

## UTF-8과 Hex Code

C++ 언어에서 파일입출력을 통해 `string` 자료형에 문자열을 저장하면, 각 요소(element)는 한 글자에 대한 정보가 아니라 1byte에 대한 정보를 담게 됩니다. 하지만 UTF-8은 1byte에서 4byte까지 다양한 크기의 byte를 사용하여 유니코드 문자를 표현하기 때문에 어떤 요소부터 어떤 요소까지가 한 글자에 대한 정보인지 글자의 경계를 찾아야 하고, 이것이 구체적으로 해결해야 할 문제였습니다.

UTF-8으로 인코딩된 "SPARCS 최고!"라는 문자열을 디코딩하는 과정에서 소괄호로 글자의 경계를 표현해 보면 아래와 같습니다.

```
UTF-8-encoded: \x53\x50\x41\x52\x43\x53\x20\xEC\xB5\x9C\xEA\xB3\xA0\x21

\x53\x50\x41\x52\x43\x53\x20\xEC\xB5\x9C\xEA\xB3\xA0\x21
-> (\x53)(\x50)(\x41)(\x52)(\x43)(\x53)(\x20)(\xEC\xB5\x9C)(\xEA\xB3\xA0)(\x21)
-> (S)(P)(A)(R)(C)(S)( )(최)(고)(!)
-> SPARCS 최고!

UTF-8-decoded: SPARCS 최고!
```

[UTF-8 encoder/decoder](https://mothereff.in/utf-8)에서 직접 테스트해볼 수도 있습니다!

## 글자의 경계 찾기

UTF-8로 인코딩된 Binary Code는 다음과 같은 규칙을 갖습니다.

|UTF-8 encoded (Binary Code)|설명|
|:--------------------------|:--|
|`0xxxxxxx`|ASCII와 동일한 범위|
|`110xxxxx 10xxxxxx`|첫 byte는 `110`, 나머지 byte들은 `10`으로 시작|
|`1110xxxx 10xxxxxx 10xxxxxx`|첫 byte는 `1110`, 나머지 byte들은 `10`으로 시작|
|`11110xxx 10xxxxxx 10xxxxxx 10xxxxxx`|첫 byte는 `1111`, 나머지 byte들은 `10`으로 시작|


따라서 글자의 첫 byte로 해당 글자가 몇 byte인지 알 수 있게 됩니다!

|첫 byte (Hex Code)|글자의 길이|
|:-------------------:|:--------:|
|`\0?`~`\7?`|1byte|
|`\8?`~`\B?`|불가능|
|`\C?`~`\D?`|2byte|
|`\E?`|3byte|
|`\F?`|4byte|

위의 표는 첫 byte만으로 글자의 경계를 찾는 방법을 대략적으로 정리한 것이지만, 실제로는 나머지 byte의 Binary Code가 `10`으로 시작하는 조건과 같이 유효한 UTF-8 인코딩 문자열인지 확인하기 위해서는 추가적인 확인이 필요하고, 이는 조건문들을 통해서 확인할 수 있습니다.