Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 2개 있습니다.)
(시리즈 글이 12개 있습니다.)
.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

닷넷: 2307. C# - 윈도우에서 한글(및 유니코드)을 포함한 콘솔 프로그램을 컴파일 및 실행하는 방법
; https://www.sysnet.pe.kr/2/0/13794

개발 환경 구성: 731. 유니코드 - 출력 예시 및 폰트 찾기
; https://www.sysnet.pe.kr/2/0/13798

개발 환경 구성: 732. 모바일 웹 브라우저에서 유니코드 문자가 표시되지 않는 경우
; https://www.sysnet.pe.kr/2/0/13799

닷넷: 2310. .NET의 Rune 타입과 emoji 표현
; https://www.sysnet.pe.kr/2/0/13813




유니코드의 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 프로젝트입니다.)




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 11/2/2024]

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

비밀번호

댓글 작성자
 




... 91  92  93  94  95  96  97  98  99  100  101  102  103  104  [105]  ...
NoWriterDateCnt.TitleFile(s)
11299정성태9/9/201719683개발 환경 구성: 330. Hyper-V VM의 Internal Network를 Private 유형으로 만드는 방법
11298정성태9/8/201723002VC++: 119. EnumProcesses / EnumProcessModules API 사용 시 주의점 [1]
11297정성태9/8/201719652디버깅 기술: 96. windbg - 풀 덤프에 포함된 모든 닷넷 모듈을 파일로 저장하는 방법
11296정성태9/8/201722867웹: 36. Edge - "이 웹 사이트는 이전 기술에서 실행되며 Internet Explorer에서만 작동합니다." 끄는 방법
11295정성태9/7/201720253디버깅 기술: 95. Windbg - .foreach 사용법
11294정성태9/4/201720015개발 환경 구성: 329. 마이크로소프트의 CoreCLR 프로파일러 예제 빌드 방법 [1]
11293정성태9/4/201720549개발 환경 구성: 328. Visual Studio(devenv.exe)를 배치 파일(.bat)을 통해 실행하는 방법
11292정성태9/4/201718813오류 유형: 419. Cannot connect to WMI provider - Invalid class [0x80041010]
11291정성태9/3/201720683개발 환경 구성: 327. 아파치 서버 2.4를 위한 mod_aspdotnet 마이그레이션
11290정성태9/3/201723907개발 환경 구성: 326. 아파치 서버에서 ASP.NET을 실행하는 mod_aspdotnet 모듈 [2]
11289정성태9/3/201721550개발 환경 구성: 325. GAC에 어셈블리 등록을 위해 gacutil.exe을 사용하는 경우 주의 사항
11288정성태9/3/201718255개발 환경 구성: 324. 윈도우용 XAMPP의 아파치 서버 구성 방법
11287정성태9/1/201727492.NET Framework: 680. C# - 작업자(Worker) 스레드와 UI 스레드 [11]
11286정성태8/28/201714818기타: 67. App Privacy Policy
11285정성태8/28/201723418.NET Framework: 679. C# - 개인 키 보안의 SFTP를 이용한 파일 업로드파일 다운로드1
11284정성태8/27/201721432.NET Framework: 678. 데스크톱 윈도우 응용 프로그램에서 UWP 라이브러리를 이용한 비디오 장치 열람하는 방법 [1]파일 다운로드1
11283정성태8/27/201717218오류 유형: 418. CSS3117: @font-face failed cross-origin request. Resource access is restricted.
11282정성태8/26/201719674Math: 22. 행렬로 바라보는 피보나치 수열
11281정성태8/26/201721471.NET Framework: 677. Visual Studio 2017 - NuGet 패키지를 직접 참조하는 PackageReference 지원 [2]
11280정성태8/24/201718513디버깅 기술: 94. windbg - 풀 덤프에 포함된 모든 모듈을 파일로 저장하는 방법
11279정성태8/23/201730159.NET Framework: 676. C# Thread가 Running 상태인지 아는 방법
11278정성태8/23/201718268오류 유형: 417. TFS - Warning - Unable to refresh ... because you have a pending edit. [1]
11277정성태8/23/201719511오류 유형: 416. msbuild - error MSB4062: The "TransformXml" task could not be loaded from the assembly
11276정성태8/23/201723816.NET Framework: 675. C# - (파일) 확장자와 연결된 실행 파일 경로 찾기 [2]파일 다운로드1
11275정성태8/23/201732811개발 환경 구성: 323. Visual Studio 설치 없이 빌드 환경 구성 - Visual Studio 2017용 Build Tools [1]
11274정성태8/22/201719372.NET Framework: 674. Thread 타입의 Suspend/Resume/Join 사용 관련 예외 처리
... 91  92  93  94  95  96  97  98  99  100  101  102  103  104  [105]  ...