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

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

1  2  3  [4]  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13528정성태1/14/20242033Linux: 68. busybox 컨테이너에서 실행 가능한 C++, Go 프로그램 빌드
13527정성태1/14/20241961오류 유형: 892. Visual Studio - Failed to launch debug adapter. Additional information may be available in the output window.
13526정성태1/14/20242051닷넷: 2201. C# - Facebook 연동 / 사용자 탈퇴 처리 방법
13525정성태1/13/20242021오류 유형: 891. Visual Studio - Web Application을 실행하지 못하는 IISExpress
13524정성태1/12/20242066오류 유형: 890. 한국투자증권 KIS Developers OpenAPI - GW라우팅 중 오류가 발생했습니다.
13523정성태1/12/20241889오류 유형: 889. Visual Studio - error : A project with that name is already opened in the solution.
13522정성태1/11/20242030닷넷: 2200. C# - HttpClient.PostAsJsonAsync 호출 시 "Transfer-Encoding: chunked" 대신 "Content-Length" 헤더 처리
13521정성태1/11/20242110닷넷: 2199. C# - 한국투자증권 KIS Developers OpenAPI의 WebSocket Ping, Pong 처리
13520정성태1/10/20241858오류 유형: 888. C# - Unable to resolve service for type 'Microsoft.Extensions.ObjectPool.ObjectPool`....'
13519정성태1/10/20241939닷넷: 2198. C# - Reflection을 이용한 ClientWebSocket의 Ping 호출파일 다운로드1
13518정성태1/9/20242175닷넷: 2197. C# - ClientWebSocket의 Ping, Pong 처리
13517정성태1/8/20242017스크립트: 63. Python - 공개 패키지를 이용한 위성 이미지 생성 (pystac_client, odc.stac)
13516정성태1/7/20242104닷넷: 2196. IIS - AppPool의 "Disable Overlapped Recycle" 옵션의 부작용
13515정성태1/6/20242377닷넷: 2195. async 메서드 내에서 C# 7의 discard 구문 활용 사례 [1]
13514정성태1/5/20242065개발 환경 구성: 702. IIS - AppPool의 "Disable Overlapped Recycle" 옵션
13513정성태1/5/20242006닷넷: 2194. C# - WebActivatorEx / System.Web의 PreApplicationStartMethod 특성
13512정성태1/4/20241979개발 환경 구성: 701. IIS - w3wp.exe 프로세스의 ASP.NET 런타임을 항상 Warmup 모드로 유지하는 preload Enabled 설정
13511정성태1/4/20241997닷넷: 2193. C# - ASP.NET Web Application + OpenAPI(Swashbuckle) 스펙 제공
13510정성태1/3/20241937닷넷: 2192. C# - 특정 실행 파일이 있는지 확인하는 방법 (Linux)
13509정성태1/3/20241966오류 유형: 887. .NET Core 2 이하의 프로젝트에서 System.Runtime.CompilerServices.Unsafe doesn't support netcoreapp2.0.
13508정성태1/3/20242016오류 유형: 886. ORA-28000: the account is locked
13507정성태1/2/20242702닷넷: 2191. C# - IPGlobalProperties를 이용해 netstat처럼 사용 중인 Socket 목록 구하는 방법파일 다운로드1
13506정성태12/29/20232191닷넷: 2190. C# - 닷넷 코어/5+에서 달라지는 System.Text.Encoding 지원
13505정성태12/27/20232707닷넷: 2189. C# - WebSocket 클라이언트를 닷넷으로 구현하는 예제 (System.Net.WebSockets)파일 다운로드1
13504정성태12/27/20232322닷넷: 2188. C# - ASP.NET Core SignalR로 구현하는 채팅 서비스 예제파일 다운로드1
13503정성태12/27/20232191Linux: 67. WSL 환경 + mlocate(locate) 도구의 /mnt 디렉터리 검색 문제
1  2  3  [4]  5  6  7  8  9  10  11  12  13  14  15  ...