Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

(시리즈 글이 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




Raymond Chen이 한글날에 밝히는 윈도우의 한글 자모 분리 현상

우리에게는 "레이몬드 첸의 윈도우 개발 282 스토리"라는 책의 저자로 알려진 Raymond Chen이 이번에는 한글날에 맞춰 윈도우의 한글 자모 분리 현상에 대한 뒷이야기를 남겼습니다.

A consequence of being the first to adopt a standard is that you may end up being the only one to adopt it: The sad story of Korean jamo
; https://devblogs.microsoft.com/oldnewthing/20201009-00/?p=104351

우선 이해를 돕기 위해, 한글 문자를 맥과 윈도우에서 표현하는 방법을 알아보겠습니다.

윈도우의 경우, 가령 '각'이라는 문자를 '각'을 나타내는 0xAC01 2바이트로 나타냅니다.

[윈도우]
 - U+AC01 '각'

반면 맥의 경우에는 '각'이라는 문자를 각각의 초성, 중성, 종성을 따로 분리해 표현을 하지만, 화면에 보여줄 때는 '각'이라고 합쳐서 보여줍니다.

[맥]
 - U+1100 'ᄀ'
 - U+1161 'ᅡ'
 - U+11A8 'ᆨ'

즉, 윈도우의 경우에는 '각'을 표현하기 위해 2바이트가 필요한 반면, 맥의 경우에는 6바이트가 필요(현실적으로는 UTF-8 인코딩을 하므로 윈도우는 3바이트, 맥은 9바이트)합니다. 이것을 유니코드의 정규화 관점에서 보면, 윈도우는 "NFC"를 따르고 맥의 경우에는 "NFD"를 따른다고 설명합니다.

문제는, ICU(Internationl Components for Unicode)도, iOS도, Android도 모두 U+1100, U+1161, U+11A8을 하나의 글자로 합쳐서 보여주는데, 왜 윈도우만 그것을 곧이곧대로 'ᄀ ᅡᆨ'으로 보여주냐는 것입니다. Raymond Chend은 이에 대해 '가장 먼저 표준을 도입하는 선발 주자로써 겪게 되는 아픔'의 한 사례라고 합니다. 실제로, 윈도우는 당시 한국의 산업 표준인 "KS X 1026"에 따라 NFC 방식이 되었다고 합니다.

Korean standard KS X 1026
; http://unicode.org/L2/L2008/08225-n3422.pdf

위의 문서에 "4. KS x 1026-1"을 보면,

  1. Modern Hangul Syllable Blocks - Only code positions of Wanseong (Precomposed) Hangul Syllable block (UAC00 ~ D7A3)
  2. Old Hangul Syllable Blocks - Only code positions of Johab Hangul Jamo block (U11xx)
  3. Two or more code positions of simple letters cannot be concatenated to represent a complex letter.
  4. A Wanseong Syllable block (UAC00 ~ UD7A3) and Johab Hangul letter(s) (U11xx) cannot be concatenated to represent another Hangul Syllable block. Ÿ Implementation algorithms for separating, searching, sorting and normalizing Hangul text syllables.

(3번과 4번은 차치하고) 현대 한글은 "Hangul Syllables"에 해당하는 AC00 ~ D7A3 범위의 완성형 코드를 쓰되, 옛한글(Old Hangul Syllable Blocks)은 "Hangul Jamo"에 해당하는 1100 ~ 11FF 범위의 조합형 코드로 쓴다고 언급이 됩니다. 즉, 일반적인 한글에 해당하는 '각'은 'ᄀ', 'ᅡ', 'ᆨ'로 따로 보관하지 않고 '각(U+AC01)'이라는 2바이트 완성형 한글을 쓰고, 옛 한글 - 예를 들어 '가ᇫ'이라는 글자는 맥에서처럼 "U+1100 U+1161 U+11EB"의 조합형으로 나타내라는 것입니다.

위키백과 문서를 보면 이에 대해 더 쉬운 설명을 포함하고 있는데요,

KS X 1026-1
; https://ko.wikipedia.org/wiki/KS_X_1026-1

위의 문서에 "금지된 조합"을 보면,

1) 조합형 한글 낱자 여러 개를 이용하여 겹낱자를 표현하지 않는다.
    예: ᄖ U+1116 (O),  U+1102 U+1107 (X)

2) 현대 한글 완성자는 반드시 한글 글자 마디(Hangul Syllables, U+AC00~U+D7AF) 영역의 문자로 표현해야 하며, 조합형 한글 낱자로 표현하지 않는다.
    예: 한 U+D55C (O), ᄒ ᅡ ᆫ U+1112 U+1161 U+11AB (X)

3) 옛한글 완성자를 표현할 때 한글 글자 마디 영역의 문자와 조합형 한글 낱자를 섞지 않는다.
    예: 가ᇫ U+1100 U+1161 U+11EB (O), 가ㅿ U+AC00 U+11EB (X)

두 번째 항목이 실제로 많이 볼 수 있는 맥의 표현으로 분명히 "KS X 1026-1" 표준 문서에는 그렇게 하지 말라고 명시하고 있습니다.

이런 설명과 함께, Raymond Chen은 윈도우가 잘못된 이유를 물을 것이 아니라, 오히려 다른 운영체제들의 잘못된 이유를 물어야 한다고 합니다. 즉, 아무도 지키지 않는 표준을 구현한 운영체제들 속에 단 하나의 표준을 구현한 운영체제가 잘못된 것처럼 보이게 된 것입니다.

어쨌든 결국, 이런 상황으로 인해 윈도우가 따르는 공식적인 표준인 NFC 방식과, 그 외의 운영체제들이 따르는 사실상의 표준인 NFD 방식으로 나뉘게 되었다고.




저 스스로가 개발자이다 보니, 사실 개인적인 관점에서 보면 만약 한글을 구현해야 했다면 NFD 방식을 따랐을 것입니다. 왜냐하면... ^^; 그것이 더 구현이 쉽습니다. 완성형 한글 속에서 옛 한글은 조합형으로 표현해야 하는 "KS X 1026-1" 표준보다는 무조건 조합형으로 구현하는 NFD 방식이 확실히 구현상 쉽다는 이점이 있습니다.

그나저나, 여기서 글을 맺으면 좀 아쉽고 Raymond Chen의 글에 달린 덧글에 보면 반박글이 재미있습니다. 즉, 맥과 같은 운영체제들이 구현한 방식이 표준이 아니라고 하는데 사실 유니코드 표준에 NFD 방식의 구현이 "UAX #29" 문서로 명확하게 나와 있다는 것입니다.

Unicode® Standard Annex #29
; http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries

(혹시... 저 현란한 문서 좀 정리해 주실 분 계실까요? ^^)

하지만 이에 대해서는 개인적으로 의문인 것이, 해당 문서의 초판 작성자가 "Authors Mark Davis (mark.davis@us.ibm.com)"으로 나오는데, 과연 저 문서를 작성할 때 한글 관련 부분에 대해 한국 측의 의견을 얼마나 잘 반영했느냐입니다. 혹시 이에 대한 이력을 아시는 한글 관련 전문가가 계시다면 덧글 부탁드리겠습니다. ^^




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







[최초 등록일: ]
[최종 수정일: 10/21/2020]

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

비밀번호

댓글 작성자
 



2020-10-14 04시44분
'샾' 등 한글 표현 문제 해결을 위한 공공 정보시스템 한글 처리 가이드라인
; http://m.korea.kr/expertWeb/resources/files/data/document_file/2010/공공%20정보시스템%20한글%20처리%20가이드라인.pdf

"
유니코드에서 한글 표현의 경우 KS X 1026-1으로 표준화되어 있고, 기술표준원 산하 문자코드위원회에서 이를 권고하고 있다
"
정성태
2021-10-20 08시46분
정성태
2022-09-29 04시17분
제 글로 인해 이런 논쟁이 발생했군요. (아마도!)

맥의 한글 파일명 분리에 대한 오해
; https://www.clien.net/service/board/park/17595712

심지어, "'가장 먼저 표준을 도입하는 선발 주자로써 겪게 되는 아픔'의 한 사례"라고 제가 의역한 문장까지 그대로 자신의 문장인 것처럼 사용하는 덧글도 보이고.
정성태

... 46  47  48  49  50  51  52  53  54  55  [56]  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12236정성태6/19/202010472오류 유형: 621. .NET Standard 대상으로 빌드 시 dynamic 예약어에서 컴파일 오류 - error CS0656: Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'
12235정성태6/19/202010097오류 유형: 620. Windows 10 - Inaccessible boot device 블루 스크린
12234정성태6/19/20209817개발 환경 구성: 494. NuGet - nuspec의 패키지 스키마 버전(네임스페이스) 업데이트 방법
12233정성태6/19/20209537오류 유형: 619. SQL 서버 - The transaction log for database '...' is full due to 'LOG_BACKUP'. - 두 번째 이야기
12232정성태6/19/20208486오류 유형: 618. SharePoint - StoreBusyRetryLater 오류
12231정성태6/15/202010994.NET Framework: 911. Console/Service Application을 위한 SynchronizationContext - AsyncContext
12230정성태6/15/202010337오류 유형: 617. IMetaDataImport::GetMethodProps가 반환하는 IL 코드 주소(RVA) 문제
12229정성태6/13/202012171.NET Framework: 910. USB/IP PROJECT를 이용해 C#으로 USB Keyboard + Mouse 가상 장치 만들기 [1]
12228정성태6/12/202012257.NET Framework: 909. C# - Source Generator를 적용한 XmlCodeGenerator파일 다운로드1
12227정성태6/12/202016248오류 유형: 616. Visual Studio의 느린 업데이트 속도에 대한 원인 분석 [5]
12226정성태6/11/202013514개발 환경 구성: 493. OpenVPN의 네트워크 구성 [4]파일 다운로드1
12225정성태6/11/202012520개발 환경 구성: 492. 윈도우에 OpenVPN 설치 - 클라이언트 측 구성
12224정성태6/11/202020456개발 환경 구성: 491. 윈도우에 OpenVPN 설치 - 서버 측 구성 [1]
12223정성태6/9/202014394.NET Framework: 908. C# - Source Generator 소개 [10]파일 다운로드2
12222정성태6/3/202010262VS.NET IDE: 146. error information: "CryptQueryObject" (-2147024893/0x80070003)
12221정성태6/3/202010005Windows: 170. 비어 있지 않은 디렉터리로 symbolic link(junction) 연결하는 방법
12220정성태6/3/202012485.NET Framework: 907. C# DLL로부터 TLB 및 C/C++ 헤더 파일(TLH)을 생성하는 방법
12219정성태6/1/202011577.NET Framework: 906. C# - lock (this), lock (typeof(...))를 사용하면 안 되는 이유파일 다운로드1
12218정성태5/27/202011488.NET Framework: 905. C# - DirectX 게임 클라이언트 실행 중 키보드 입력을 감지하는 방법 [3]
12217정성태5/24/20209949오류 유형: 615. Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 0, current count = 1.
12216정성태5/15/202013114.NET Framework: 904. USB/IP PROJECT를 이용해 C#으로 USB Keyboard 가상 장치 만들기 [14]파일 다운로드1
12215정성태5/12/202018173개발 환경 구성: 490. C# - (Wireshark의) USBPcap을 이용한 USB 패킷 모니터링 [10]파일 다운로드1
12214정성태5/5/202010461개발 환경 구성: 489. 정식 인증서가 있는 경우 Device Driver 서명하는 방법 (2) - UEFI/SecureBoot [1]
12213정성태5/3/202012115개발 환경 구성: 488. (User-mode 코드로 가상 USB 장치를 만들 수 있는) USB/IP PROJECT 소개
12212정성태5/1/20209792개발 환경 구성: 487. UEFI / Secure Boot 상태인지 확인하는 방법
12211정성태4/27/202012135개발 환경 구성: 486. WSL에서 Makefile로 공개된 리눅스 환경의 C/C++ 소스 코드 빌드
... 46  47  48  49  50  51  52  53  54  55  [56]  57  58  59  60  ...