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




C# - 같은 모양, 다른 값의 한글 자음을 비교하는 호환 분해

다음과 같은 질문이 있군요. ^^

문자 질문입니다.
; https://www.sysnet.pe.kr/3/0/5065

위 질문에 링크된 글이 재미있습니다.

같은 모양, 다른 값의 한글 자음
; http://winplz.tistory.com/entry/%ED%95%9C%EA%B8%80-%EC%9E%90%EC%9D%8C-%EB%B9%84%EA%B5%90%EA%B0%99%EC%A7%80%EB%A7%8C-%EB%8B%A4%EB%A5%B8-%EC%9E%90%EC%9D%8C%EB%93%A4

위의 글은 iOS의 Objective C나 Swift 환경으로 설명하는 것 같은데, 닷넷 환경으로 질문을 다시 옮겨 보면 이렇습니다.

{
    string txt1 = "ㄱ";
    string txt2 = "각";

    String nfd = txt1.Normalize(System.Text.NormalizationForm.FormD);
    String nfc = txt2.Normalize(System.Text.NormalizationForm.FormD);

    Console.WriteLine(nfd + ": " + (int)nfd[0]);
    Console.WriteLine(nfc[0] + ": " + (int)nfc[0]);
}

/*
출력 결과:

ㄱ: 12593
ㄱ: 4352
*/

출력 결과가 상이한데, 처음의 'ㄱ'은 한글 자음을 나타내는 문자(유니코드 심벌 명은 "Hangul Letter Kiyeok")이고 두 번째 줄의 경우는 약간 '위 첨자' 식으로 상단에 살짝 떠 있는 초성에서의 'ㄱ'(유니코드 심벌 명은 "Hangul Choseong Kiyeok")을 나타냅니다. 따라서, 어찌 보면 당연히 달라야 하지만 '자음 입력에 따른 검색 엔진'을 구현하는 경우에는 이 결과가 그다지 바람직하지 않습니다.

재미있는 것은, 2개의 문자가 속한 "Unicode Group"입니다.

[그림: "Hangul Jamo"에 속한 "Hangul Letter Kiyeok"]
hangul_unicode_jamo_0.png

[그림: "Hangul Compatibility Jamo"에 속한 "Hangul Choseong Kiyeok"]
hangul_unicode_jamo_1.png

"Hangul Compatibility Jamo"의 wikipedia 설명을 보면,

Hangul Compatibility Jamo
; https://en.wikipedia.org/wiki/Hangul_Compatibility_Jamo

Hangul Compatibility Jamo is a Unicode block containing Hangul characters for compatibility with Korean Standard KS X 1001:1998.

"Hangul Compatibility Jamo" 영역의 문자들은 KS X 1001:1998 표준과 호환하는 글자를 포함한다고 합니다.

KS X 1001
; https://en.wikipedia.org/wiki/KS_X_1001

위의 문서를 보면, KS X 1001은 "KSC-5601"로 불렸던 한글 문자 셋의 새 이름인데, KSC-5601 문자 셋과의 호환을 위해 특별히 유니코드에서 별도로 "Hangul Compatibility Jamo" 그룹에 배치했다는 정도로 받아들이면 되겠습니다.




다시 문제로 돌아와서, 그러니까 텍스트 박스에 글자를 입력할 때 'ㄱ' 글자만을 입력한 경우 유니코드 상의 값은 12593(0x3131: 한글 호환 자모의 'ㄱ')인 반면 검색해야 할 문자열에 포함된 글자들은 초성으로써의 'ㄱ'이기 때문에 값의 비교를 할 수 없다는 것입니다.

당연히 이 문제를 해결하려면 '정규화'를 해야 하고, 정규화 시 글자의 분해를 '정준 분해'가 아닌 '호환 분해'를 하면 됩니다. 따라서 다음과 같이 코딩하는 것으로 해결할 수 있습니다.

{
    string txt1 = "ㄱ";
    string txt2 = "각";

    String nfd = txt1.Normalize(System.Text.NormalizationForm.FormKD);
    String nfc = txt2.Normalize(System.Text.NormalizationForm.FormKD);

    Console.WriteLine(nfd + ": " + (int)nfd[0]);
    Console.WriteLine(nfc[0] + ": " + (int)nfc[0]);
}

/*
출력 결과:

ㄱ: 4352
ㄱ: 4352
*/

보는 바와 같이 2개 모두 (단 자음으로서의 'ㄱ'이 아닌) '초성'으로서의 'ㄱ'으로 값을 비교할 수 있습니다. 자바의 경우에도 Normalizer.normalize 메서드를 지원하므로 Normalizer.Form.NFD 옵션으로 분해해 해결할 수 있습니다.




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 10/5/2018]

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

비밀번호

댓글 작성자
 



2018-10-04 12시33분
[키모] 혹시 반대로 4352의 값을 12593으로 할려면 어떻게 해야하나요?string txt2 = "각"을
String nfc = txt2.Normalize(System.Text.NormalizationForm.FormD);을 했을경우 4352로
나오던데 혹시 반대로 할려면 어떻게 해야할까요?
[guest]
2018-10-04 01시04분
[정환] "각"을 초성 중성 종성으로 분리해서 유니코드로 캐스팅하면 되지 않을까요?
[guest]
2018-10-04 06시45분
[키모] 저 자체가 같은 유니코드인데 값이 다르다는 말씀이신거 같은거 같은데 캐스팅이랑은 다르지 않을까요?
[guest]
2018-10-05 10시43분
다음의 글을 참고하세요.

유니코드와 한글 - "Hangul Compatibility Jamo"
; http://www.sysnet.pe.kr/2/0/11724
정성태
2018-10-07 03시56분
[키모] 아 감사합니다 확인해보겠습니다. :)
[guest]

... 76  77  78  79  80  81  82  83  84  [85]  86  87  88  89  90  ...
NoWriterDateCnt.TitleFile(s)
11518정성태5/10/201811975.NET Framework: 747. C# 7.0에서도 부분적으로 가능해진 "타입 추론을 통한 튜플의 변수명 자동 지정"
11517정성태5/10/201812404.NET Framework: 746. Azure runbook 예제 - 6시간 동안 수행 중인 VM을 중지 [1]파일 다운로드1
11516정성태5/9/201812122.NET Framework: 745. Azure runbook을 PowerShell 또는 C# 코드로 실행하는 방법파일 다운로드1
11515정성태5/9/201814051.NET Framework: 744. C# 6 - Expression bodied function [1]
11514정성태5/3/201813096오류 유형: 466. Bitvise - Error in component session/transport/kexHandler [2]
11513정성태5/3/201818486.NET Framework: 743. C# 언어의 공변성과 반공변성 [9]파일 다운로드2
11512정성태5/2/201811869개발 환경 구성: 375. Azure runbook 실행 시 "Errors", "All Logs"에 오류 메시지가 출력되는 경우
11511정성태5/2/201813741개발 환경 구성: 374. Azure - Runbook 기능 소개
11510정성태4/30/201815206.NET Framework: 742. windbg로 확인하는 Finalizer를 가진 객체의 GC 과정파일 다운로드1
11509정성태4/28/201812764.NET Framework: 741. windbg로 확인하는 객체의 GC 여부
11508정성태4/23/201814278개발 환경 구성: 373. MSBuild를 이용해 프로젝트 배포 후 결과물을 zip 파일로 압축하는 방법파일 다운로드1
11507정성태4/20/201814304개발 환경 구성: 372. MSBuild - 빌드 전/후, 배포 전/후 실행하고 싶은 Task 정의
11506정성태4/20/201818185.NET Framework: 740. C#에서 enum을 boxing 없이 int로 변환하기 - 두 번째 이야기 [7]파일 다운로드1
11505정성태4/19/201811572개발 환경 구성: 371. Azure Web App 확장 예제 - Simple WebSite Extension
11504정성태4/19/201812855오류 유형: 465. Azure Web App 확장 - Extplorer File manager 적용 시 오류
11503정성태4/19/201813698오류 유형: 464. PowerShell - Start-Service 명령 오류 (Service 'xxx' cannot be started)
11502정성태4/17/201814648개발 환경 구성: 370. Azure VM/App Services(Web Apps)에 Let's Encrypt 무료 인증서 적용 방법 [3]
11501정성태4/17/201811662개발 환경 구성: 369. New-AzureRmADServicePrincipal로 생성한 계정의 clientSecret, key 값을 구하는 방법파일 다운로드1
11500정성태4/17/201812588개발 환경 구성: 368. PowerShell로 접근하는 Azure의 Access control 보안과 Azure Active Directory의 계정 관리 서비스
11499정성태4/17/201811575개발 환경 구성: 367. Azure - New-AzureRmADServicePrincipal / New-AzureRmRoleAssignment 명령어
11498정성태4/17/201811276개발 환경 구성: 366. Azure Active Directory의 사용자 유형 구분 - Guest/Member
11497정성태4/17/20189682개발 환경 구성: 365. Azure 리소스의 액세스 제어(Access control) 별로 사용자에게 권한을 할당하는 방법 [2]
11496정성태4/17/201810119개발 환경 구성: 364. Azure Portal에서 구독(Subscriptions) 메뉴가 보이지 않는 경우
11495정성태4/16/201812505개발 환경 구성: 363. Azure의 Access control 보안과 Azure Active Directory의 계정 관리 서비스
11494정성태4/16/20189807개발 환경 구성: 362. Azure Web Apps(App Services)에 사용자 DNS를 지정하는 방법
11493정성태4/16/201811379개발 환경 구성: 361. Azure Web App(App Service)의 HTTP/2 프로토콜 지원
... 76  77  78  79  80  81  82  83  84  [85]  86  87  88  89  90  ...