Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)
(시리즈 글이 8개 있습니다.)
.NET Framework: 326. 유니코드와 한글 - 유니코드와 닷넷을 이용한 한글 처리
; https://www.sysnet.pe.kr/2/0/1294

.NET Framework: 411. 유니코드의 "compatibility character"가 뭘까요?
; https://www.sysnet.pe.kr/2/0/1607

.NET Framework: 429. C# - 유니코드 한글 문자열을 ks_c_5601-1987로 변환하는 방법
; https://www.sysnet.pe.kr/2/0/1657

개발 환경 구성: 230. 유니코드의 Surrogate Pair, Supplementary Characters가 뭘까요?
; https://www.sysnet.pe.kr/2/0/1710

.NET Framework: 450. 영문 윈도우에서 C# 콘솔 프로그램의 유니코드 출력 방법
; https://www.sysnet.pe.kr/2/0/1712

.NET Framework: 794. C# - 같은 모양, 다른 값의 한글 자음을 비교하는 호환 분해
; https://www.sysnet.pe.kr/2/0/11710

개발 환경 구성: 407. 유니코드와 한글 - "Hangul Compatibility Jamo"
; https://www.sysnet.pe.kr/2/0/11724

Windows: 176. Raymond Chen이 한글날에 밝히는 윈도우의 한글 자모 분리 현상
; https://www.sysnet.pe.kr/2/0/12369




유니코드의 Surrogate Pair, Supplementary Characters가 뭘까요?

유니코드와 한글 - 유니코드와 닷넷을 이용한 한글 처리
; https://www.sysnet.pe.kr/2/0/1294

유니코드의 "compatibility character"가 뭘까요?
; https://www.sysnet.pe.kr/2/0/1607

위의 글도 읽어보시면 좋겠지요. ^^ 오늘은 유니코드의 Surrogate Pair, Supplementary Characters에 대한 용어를 설명해 보겠습니다.

혹시 여러분들은 2바이트 UTF-16 코드가 어떻게 6만 5천 글자를 넘어서는 글자들을 표현할 수 있는지에 대해 궁금하지 않으셨나요? 분명히 유니코드는 4바이트 영역을 쓰기로 작정한 문자셋이므로 16비트로 표현하기에는 역부족입니다. 바로 그 해결책이 Surrogate Pair입니다.

Surrogate Pair는 마이크로소프트의 MSDN 문서에 보면 다음과 같이 친절하게 설명되어 있습니다.

Surrogates and Supplementary Characters
; https://learn.microsoft.com/en-us/windows/win32/intl/surrogates-and-supplementary-characters

우선 Supplementary Characters는 유니코드의 2바이트 기본 범위에 속하는 BMP(Basic Multilingual Plane: Plane 0) 영역을 넘어선 글자들이라고 합니다. 그리고 Surrogate Pair는 이 범주에 속하는 Supplementary Characters를 표현하기 위해 UTF-16에 도입된 인코딩 방식입니다.

^^ 그러고 보니, 아래의 글에서도 Surrogate Pair에 해당하는 문자를 다루고 지나갔었습니다.

유니코드와 한글 - 유니코드와 닷넷을 이용한 한글 처리
; https://www.sysnet.pe.kr/2/0/1294

바로 U+10000 과 U+10001 2개의 글자가 Surrogate Pair 방식으로 표현되었던 것입니다.

Unicode Character 'LINEAR B SYLLABLE B008 A' (U+10000)
; http://www.fileformat.info/info/unicode/char/10000/index.htm

Unicode Character 'LINEAR B SYLLABLE B038 E' (U+10001)
; http://www.fileformat.info/info/unicode/char/10001/index.htm

위의 2개 문자를 보면 값이 2바이트 영역을 넘어서고 있습니다. 즉, U+10000 과 U+10001 글자들은 Supplementary Characters에 해당합니다. 그리고 해당 문자들을 표현하기 위해 각각 다음과 같이 2개의 UTF-16 코드가 할당되어 있습니다.

U+10000: \uD800 \uDC00
U+10001: \uD800 \uDC01

여기서 왜 "Pair"라고 하는지 밝혀집니다. 즉, 2바이트 영역을 넘어서는 글자 하나를 표현하기 위해 2개의 2바이트가 사용된 것입니다.

그런데, 위의 0xd800, 0xdc00, 0xdc01 코드로 이미 기존에 할당된 문자들과는 그럼 어떻게 구분한다는 말입니까? 물론, 코드를 아무거나 사용할 수는 없지요. 그래서 원래 UTF-16인코딩에서 U+D800 ~ U+DFFF 사이의 2048 글자 영역은 비어 있었습니다. 그리고 이를 절반씩 1024개로 나눠서 pair의 앞글자와 뒷글자 영역을 담당하게 한 것입니다. 즉, surrogate pair는 다음의 쌍으로 이뤄집니다.

[0xd800 ~ 0xdbff] [0xdc00 ~ 0xdfff]

Pair의 앞 글자에 1024개의 경우의 수가 나오고 뒤의 글자에도 역시 1024개의 경우의 수가 나오므로 이를 조합하면 1,048,576으로 약 100만개의 글자 영역이 확보되는 것입니다. 일단, 기존의 6만 개가 넘는 글자에 100만개의 글자 영역이 추가로 확보되었으니 당분간은 외계 언어가 추가되지 않는 한 UTF-16으로 충분히 문자를 표현할 수 있을 정도는 된 것입니다. 실제로 "Surrogates and Supplementary Characters" 글에 보면 유니코드 4.1에서 9만 7천자 정도가 추가된 정도라고 합니다. (정확히 하면 UTF-16은 현재 1,114,112개의 글자를 표현할 수 있다고 합니다.)




그럼, Supplementary Characters가 자신의 컴퓨터에서 어떻게 보여질 수 있는지 간단하게 테스트를 해볼까요? ^^ (윈도우 기준으로 하겠습니다.)

우선 차이점을 느끼기 위해 현재의 환경에서 다음의 웹 페이지를 Internet Explorer (또는 Chrome)로 방문해 봅니다.

Using UTF-16 Little-Endian Plane 1 Supplementary Characters
; http://www.i18nguy.com/unicode/plane1-utf-16.html

그럼, IE 11의 경우 다음과 같이 "Linear B Syllabary", "Shavian" 영역의 글자가 비정상적으로 나오는 것을 볼 수 있습니다.

surrogate_pair_display_1.png

크롬의 경우는 다음과 같이 전체가 비정상적으로 나옵니다.

surrogate_pair_display_2.png

IE와 크롬의 차이는 아마도 웹 페이지에 포함된 "Arial Unicode MS" 폰트의 로드 차이인 것 같습니다.

td.plane1 {
font-family : CODE2001, "Arial Unicode MS", serif;
font-size    : 120%;
text-align   : left;
direction    : ltr;
color        : black;
background-color : #FFFF99;
}

IE의 경우 기본적으로 일부 유니코드를 보여줄 수 있는 "Arial Unicode MS" 폰트를 로드할 수 있는 반면 크롬은 (웬일인지?) 로드를 하지 않는 것 같습니다.

자, 그럼 이 페이지들을 정상적으로 보이기 위한 설정을 해볼까요? ^^

우선, 여러분들이 만약 윈도우 운영체제를 XP/2003이하의 버전을 쓰고 있다면 3가지 레지스트리 설정을 선행해서 처리해야 합니다. 어떤 설정인지는 다음의 글을 참고하시면 됩니다.

Setting up Microsoft Windows NT, 2000 or Windows XP to support Unicode supplementary characters
; http://www.i18nguy.com/surrogates.html
(중간에 보면, "Setting 1", "Setting 2", "Setting 3"의 레지스트리 설정이 나오는데 이를 참고하시면 됩니다.)

저는 윈도우 8.1에서 테스트 하고 있기 때문에 위의 설정을 하지 않았습니다. 그다음, 웹 브라우저가 사용할 수 있는 폰트를 시스템에 등록해야 합니다.

위의 CSS 코드에 보면 "CODE2001"이라는 폰트 명을 볼 수 있는데요. 바로 이것을 여러분들의 윈도우 시스템에 설치해야 합니다. 아쉽게도 "Using UTF-16 Little-Endian Plane 1 Supplementary Characters" 글에 링크된 "http://home.att.net/~jameskass/CODE2001.ZIP" 파일은 현재 존재하지 않습니다. 어쩔 수 없이 웹 검색을 했는데 다음의 페이지에서 발견할 수 있었습니다.

Code2001 font - Created in 1998 by James Kass 
; http://www.fontspace.com/james-kass/code2001
; http://www.fontspace.com/download/13285/2489492aa53d466d94ffc197bfe1a865/james-kass_code2001.zip

Code2001 is an experimental Plane 1 Unicode based font. The first 255 code points are as in ISO-8859-001. The balance of the code points are from Plane 1, a supplementary plane of Unicode.

다운로드 받아 압축을 풀고 "CODE2001.TTF" 파일을 탐색기에서 두번 누르면 폰트 창이 뜨는데, 상단의 "Install" 버튼을 누르면 윈도우(C:\Windows\Fonts)에 설치가 됩니다.

설치 후 인터넷 익스플로러는 재시작할 필요없이 페이지 로딩만 다시 하면 곧바로 유니코드 폰트가 보입니다. (크롬의 경우에는 종료한 후 다시 페이지를 방문해야 합니다.)

어쨌든, 두가지 웹 브라우저 모두 다음과 같이 1번 Plane 영역에 속한 "Supplementary Characters" 유니코드 문자를 잘 보여줍니다. ^^

surrogate_pair_display_3.png




그럼, C# 응용 프로그램에서는 어떻게 해야 할까요?

"Surrogates and Supplementary Characters" 글에 의하면, "Edit", "Rich Edit" 컨트롤이 "Supplementary Characters"를 지원한다고 합니다.

테스트를 위해 윈폼 프로젝트를 하나 만들고, TextBox, RichTextBox를 각각 올려 놓은 후 Form1_Load에서 다음과 같이 코딩을 해봅니다.

private void Form1_Load(object sender, EventArgs e)
{
    string text = "\uD800\uDF38";
    // 또는 text = "??";

    this.textBox1.Text = text;
    this.richTextBox1.Text = text;
}

이상하군요. TextBox의 경우에는 텍스트가 잘 보이지만, RichTextBox의 경우에는 출력을 못하고 있습니다.

surrogate_pair_display_4.png

더욱 이상한 것은 TextBox, RichTextBox 모두 기본적으로 설정된 폰트는 "Microsoft Sans Serif"였는데도 TextBox는 글자를 잘 보여주고 있습니다.

하지만, 폰트를 명시적으로 "Arial Unicode MS"로 바꿔도 여전히 RichTextBox는 출력이 안됩니다.

this.textBox1.Font = new System.Drawing.Font("Arial Unicode MS", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.richTextBox1.Font = new System.Drawing.Font("Arial Unicode MS", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

하는 김에 "유니코드와 한글 - 유니코드와 닷넷을 이용한 한글 처리" 글에서 테스트한 "Unicode Character 'LINEAR B SYLLABLE B008 A' (U+10000)", "Unicode Character 'LINEAR B SYLLABLE B038 E' (U+10001)" 2개의 문자를 넣어봤는데,

private void Form1_Load(object sender, EventArgs e)
{
    this.textBox1.Font = new System.Drawing.Font("Arial Unicode MS", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
    this.richTextBox1.Font = new System.Drawing.Font("Arial Unicode MS", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

    string text = "\uD800\uDC00\uD800\uDC01";

    this.textBox1.Text = text;
    this.richTextBox1.Text = text;
}

이번에는 "Arial Unicode MS"를 지정했는데도 불구하고 TextBox, RichTextBox 2개 모두 글자가 전혀 나오지 않습니다.

surrogate_pair_display_5.png

혹시나 폰트가 해당 영역의 글자를 포함하지 않았나 싶어서 Code2001 폰트를 Visual Studio 속성 창에서 선택해 보았는데,

surrogate_pair_display_6.png

다음과 같은 오류 메시지가 뜹니다.

"Only TrueType fonts are supported. This is not a TrueType font."

검색해 보니, 폰트 대화창의 버그라는 글이 눈에 띄는데,

Only TrueType fonts are supported. This is not a TrueType font.
; http://stackoverflow.com/questions/11551805/in-c-sharp-winform-i-got-only-truetype-fonts-are-supported-this-is-not-a-tru

비주얼 스튜디오의 속성 창에서 선택한 폰트 대화창의 코드를 제가 변경할 수는 없으므로 그 방법은 일단 포기했습니다. 그렇지만 코드를 통해 직접 지정하는 것은,

private void Form1_Load(object sender, EventArgs e)
{
    this.textBox1.Font = new System.Drawing.Font("Code2001", 12F);
    this.richTextBox1.Font = new System.Drawing.Font("Code2001", 12F);

    string text = "\uD800\uDC00\uD800\uDC01";

    this.textBox1.Text = text;
    this.richTextBox1.Text = text;
}

TextBox, RichTextBox 2개에서 모두 잘 동작했습니다.

surrogate_pair_display_7.png

휴~~~ 어쨌든 다행이군요. ^^ 이것으로 Surrogate Pair, Supplementary Characters 용어에 대한 탐구는 끝이 납니다.

(첨부한 파일은 위의 테스트를 수행한 간단한 WinForm 프로젝트입니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 12/27/2022]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13600정성태4/18/2024253닷넷: 2242. C# - 관리 스레드와 비관리 스레드
13599정성태4/17/2024273닷넷: 2241. C# - WAV 파일의 PCM 사운드 재생(Windows Multimedia)파일 다운로드1
13598정성태4/16/2024288닷넷: 2240. C# - WAV 파일 포맷 + LIST 헤더파일 다운로드1
13597정성태4/15/2024365닷넷: 2239. C# - WAV 파일의 PCM 데이터 생성 및 출력파일 다운로드1
13596정성태4/14/2024726닷넷: 2238. C# - WAV 기본 파일 포맷파일 다운로드1
13595정성태4/13/2024849닷넷: 2237. C# - Audio 장치 열기 (Windows Multimedia, NAudio)파일 다운로드1
13594정성태4/12/20241002닷넷: 2236. C# - Audio 장치 열람 (Windows Multimedia, NAudio)파일 다운로드1
13593정성태4/8/20241050닷넷: 2235. MSBuild - AccelerateBuildsInVisualStudio 옵션
13592정성태4/2/20241206C/C++: 165. CLion으로 만든 Rust Win32 DLL을 C#과 연동
13591정성태4/2/20241166닷넷: 2234. C# - WPF 응용 프로그램에 Blazor App 통합파일 다운로드1
13590정성태3/31/20241072Linux: 70. Python - uwsgi 응용 프로그램이 k8s 환경에서 OOM 발생하는 문제
13589정성태3/29/20241141닷넷: 2233. C# - 프로세스 CPU 사용량을 나타내는 성능 카운터와 Win32 API파일 다운로드1
13588정성태3/28/20241192닷넷: 2232. C# - Unity + 닷넷 App(WinForms/WPF) 간의 Named Pipe 통신파일 다운로드1
13587정성태3/27/20241151오류 유형: 900. Windows Update 오류 - 8024402C, 80070643
13586정성태3/27/20241294Windows: 263. Windows - 복구 파티션(Recovery Partition) 용량을 늘리는 방법
13585정성태3/26/20241094Windows: 262. PerformanceCounter의 InstanceName에 pid를 추가한 "Process V2"
13584정성태3/26/20241046개발 환경 구성: 708. Unity3D - C# Windows Forms / WPF Application에 통합하는 방법파일 다운로드1
13583정성태3/25/20241154Windows: 261. CPU Utilization이 100% 넘는 경우를 성능 카운터로 확인하는 방법
13582정성태3/19/20241413Windows: 260. CPU 사용률을 나타내는 2가지 수치 - 사용량(Usage)과 활용률(Utilization)파일 다운로드1
13581정성태3/18/20241586개발 환경 구성: 707. 빌드한 Unity3D 프로그램을 C++ Windows Application에 통합하는 방법
13580정성태3/15/20241136닷넷: 2231. C# - ReceiveTimeout, SendTimeout이 적용되지 않는 Socket await 비동기 호출파일 다운로드1
13579정성태3/13/20241493오류 유형: 899. HTTP Error 500.32 - ANCM Failed to Load dll
13578정성태3/11/20241628닷넷: 2230. C# - 덮어쓰기 가능한 환형 큐 (Circular queue)파일 다운로드1
13577정성태3/9/20241872닷넷: 2229. C# - 닷넷을 위한 난독화 도구 소개 (예: ConfuserEx)
13576정성태3/8/20241543닷넷: 2228. .NET Profiler - IMetaDataEmit2::DefineMethodSpec 사용법
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...