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

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




C# - 유니코드 한글 문자열을 ks_c_5601-1987로 변환하는 방법

아래와 같은 질문이 있습니다.

dot net micro framework 에서 encoding 변환
; http://social.msdn.microsoft.com/Forums/ko-KR/847b2a69-b53f-43fa-8455-439f11a985c2/dot-net-micro-framework-encoding-?forum=dotnetko&prof=required

질문의 내용을 요약하면, ".NET Micro Framework"는 System.Text.Encoding.UTF8 인코딩만 지원하고 있는 데다 장비는 System.Text.Encoding.Default 인코딩으로 전송한 한글을 인식한다는 것입니다.

재미있군요. ^^ 한글 윈도우에서 System.Text.Encoding.Default 방식은 곧 ks_c_5601-1987 인코딩을 사용했다는 것입니다. 그렇다면 장비 측에서 ks_c_5601-1987 인코딩 방식의 한글을 지원한다는 것인데, 제가 FA 산업 분야는 잘 몰라서 할 말이 없지만 장비에서 다른 표준 인코딩도 아니고 국내 특화된 ks_c_5601-1987을 지원한다는 것이 의외입니다.

암튼, 그렇다고 하니... ^^ ks_c_5601-1987 인코딩을 할 수 있는 메서드를 만들어야 합니다. 일단, C#의 string 타입은 내부적으로 UTF-16 인코딩을 따르기 때문에 해당 string을 char 배열로 바꾼 다음 곧바로 바이트 배열로 뽑아내면 그건 UTF-16 인코딩이 된 결과물이 됩니다. 비교를 위해 다음과 같이 코딩을 할 수 있습니다.

using System;
using System.Collections.Generic;

namespace encode_test
{
    class Program
    {
        static void Main(string[] args)
        {
            string text = "한글 테스트";

            byte[] contents1 = System.Text.Encoding.Unicode.GetBytes(text);
            Console.WriteLine(BitConverter.ToString(contents1));

            byte[] contents2 = Chars2Bytes(text.ToCharArray());
            Console.WriteLine(BitConverter.ToString(contents2));
        }

        public static byte[] Chars2Bytes(char[] charArray)
        {
            List<byte> outputs = new List<byte>();

            for (int i = 0; i < charArray.Length; i ++)
            {
                outputs.Add((byte)(charArray[i] & 0xFF));
                outputs.Add((byte)(charArray[i] >> 8));
            }

            return outputs.ToArray();
        }
    }
}

당연히 실행 결과는 동일하게 나오겠죠? ^^

5C-D5-00-AE-20-00-4C-D1-A4-C2-B8-D2
5C-D5-00-AE-20-00-4C-D1-A4-C2-B8-D2

우리가 원하는 것은 ks_c_5601-1987이기 때문에 유니코드를 ks_c_5601-1987로 변환해주는 테이블이 필요합니다. 다행히 이를 찾아보면 다음과 같은 텍스트 파일을 구할 수 있습니다.

ksc5601.txt 
; http://opensource.apple.com/source/tcl/tcl-10/tcl/tools/encoding/ksc5601.txt

대략 다음과 같은 내용을 담고 있는데요.

# What is enclosed below is the mapping between KS C 5601-1987
# and Unicode 2.0.   It's automatically generated from KSC5601.TXT
# (at ftp://ftp.unicode.org/Public/MAPPING/EASTASIA/KSC) which is
# actually NOT the mapping between KS C 5601-1992 and Unicode 2.0
# BUT the mapping table between UHC(Microsoft Unified Hangul Code)
# and Unicode 2.0. Hence, in this pacakge, I renamed it as UHC.TXT
#
# The Unix command  used is 
# egrep '^0x' < KSC5601.TXT |   \
# egrep -v '^0x([8-9]...|A0..|..[4-9].|..A0)' | perl tab.pl
#
# where tab.pl  is as following
#----------tab.pl
#  $n=0;
#  while (<>) {
#    local($euck, $ucs4, @rest) = split;
#    local($u)=hex($ucs4);
#    local($k)=hex($euck);
#    printf ("0x%04X  0x%04X  %s\n",$k-0x8080, $u,join(' ',@rest));
#  }
#
# Column #1 : KS C 5601-1987(KS C 5601-1992 excluding addtional Hangul
#            syllables defined for Johab encoding in Annex 3)
#            in hex as 0xXXXX
# Column #2 : the Unicode (in hex as 0xXXXX)
# Column #3 : the Unicode name (following a comment sign, '#')
# The number of characters enumerated in this table is 8824, the
# as listed in KS C 5601-987
# 
# 
# The entries are in KS C 5601-1987 order
# You can use the following algorithms to convert the hex form
# of KS C 5601 to other forms
#   To get EUCKorea(EUC-KR) code points, add 0x8080.
#   To get row(Hang) and column(Yol) as used in KS C 5601-1987 manual,
#      first subtract 0x2020. Then
#      the high and low bytes correspond to the row(Hang) and the column(Yol),
#      respectively
0x2121  0x3000  # IDEOGRAPHIC SPACE
0x2122  0x3001  # IDEOGRAPHIC COMMA
0x2123  0x3002  # IDEOGRAPHIC FULL STOP
0x2124  0x00B7  # MIDDLE DOT
0x2125  0x2025  # TWO DOT LEADER
0x2126  0x2026  # HORIZONTAL ELLIPSIS
0x2127  0x00A8  # DIAERESIS

....[이하 생략]...

즉 첫 번째 컬럼의 값이 (0x8080을 더하면) "KS C 5601-1987" 값이고, 두 번째 값이 유니코드 대응입니다. 이 텍스트를 동적으로 로드해서 사용하는 것도 좋지만 보통 매핑 테이블을 만들어 두는 것이 더 효율적이기 때문에 미리 C# 코드로 변환해 두는 것이 좋습니다. 하지만, 텍스트 파일 내용이 너무 길기 때문에 일일이 변환하는 것은 불편하므로 다음과 같이 C# 코드로 출력해 주는 메서드를 이용해 파일로 만듭니다.

public static void Output()
{
    Console.WriteLine("Dictionary<char, char> unicode2ksc = new Dictionary<char,char>();");

    foreach (string line in File.ReadAllLines("ksc5601.txt"))
    {
        string[] splits = line.Split('#');
        if (splits.Length < 2 || string.IsNullOrEmpty(splits[0]) == true)
        {
            continue;
        }

        string[] ksc2unicode = splits[0].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
        if (ksc2unicode.Length < 2)
        {
            continue;
        }

        int ksc = Convert.ToInt32(ksc2unicode[0], 16) + 0x8080;
        int unicode = Convert.ToInt32(ksc2unicode[1], 16);

        Console.WriteLine(string.Format("unicode2ksc.Add((char){0}, (char){1});", unicode, ksc));
    }
}

출력된 내용을 C# 파일에 적절하게 복사하면 다음과 같이 유니코드에서 ks_c_5601-1987로 변환하는 메서드를 만들 수 있습니다.

using System;
using System.Collections.Generic;
using System.IO;

namespace encode_test
{
    public class ksc5601
    {
        static Dictionary<char, char> unicode2ksc = new Dictionary<char, char>();

        static ksc5601()
        {
            unicode2ksc.Add((char)12288, (char)41377);
            unicode2ksc.Add((char)12289, (char)41378);

            // ...[생략]...

            unicode2ksc.Add((char)32690, (char)65021);
            unicode2ksc.Add((char)35440, (char)65022);
        }

        public static byte[] unicode2ksc5601(string text)
        {
            List<byte> contents = new List<byte>();

            foreach (char ch in text)
            {
                if (unicode2ksc.ContainsKey(ch) == true)
                {
                    char ksc = (char)(unicode2ksc[ch]);
                    contents.Add((byte)(ksc >> 8));
                    contents.Add((byte)(ksc & 0xFF));
                }
                else if (ch < byte.MaxValue)
                {
                    contents.Add((byte)ch);
                }
                else
                {
                    throw new ApplicationException("Not supported character: " + ch);
                }
            }

            return contents.ToArray();
        }
    }
}

이제 System.Text.Encoding.Default와 출력이 같은지 테스트 해볼까요? ^^

string text = "한글 테스트";
{
    byte[] contents1 = System.Text.Encoding.Default.GetBytes(text);
    Console.WriteLine(BitConverter.ToString(contents1));

    byte[] contents2 = ksc5601.unicode2ksc5601(text);
    Console.WriteLine(BitConverter.ToString(contents2));
}

// 출력결과
C7-D1-B1-DB-20-C5-D7-BD-BA-C6-AE
C7-D1-B1-DB-20-C5-D7-BD-BA-C6-AE

참고로, ".NET Micro Framework"는 제네릭 구문을 지원하지 않기 때문에 위의 코드를 C# 1.0 문법으로 변환해 주어야 합니다. 그건... 각자의 숙제로!

(테스트 코드는 첨부 파일로 넣어두었습니다.)




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







[최초 등록일: ]
[최종 수정일: 11/8/2023]

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

비밀번호

댓글 작성자
 



2014-04-11 08시05분
[남동균] 도움이 많이 되었습니다.
감사합니다.
[guest]
2019-06-19 01시34분
[감사] 감사합니다!
[guest]
2021-06-10 10시33분
정성태

[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13917정성태4/30/202528VS.NET IDE: 199. Directory.Build.props에 정의한 속성에 대해 Condition 제약으로 값을 변경하는 방법
13916정성태4/23/2025430디버깅 기술: 221. WinDbg 분석 사례 - ASP.NET HttpCookieCollection을 다중 스레드에서 사용할 경우 무한 루프 현상 - 두 번째 이야기
13915정성태4/13/20251637닷넷: 2331. C# - 실행 시에 메서드 가로채기 (.NET 9)파일 다운로드1
13914정성태4/11/20251964디버깅 기술: 220. windbg 분석 사례 - x86 ASP.NET 웹 응용 프로그램의 CPU 100% 현상 (4)
13913정성태4/10/20251187오류 유형: 950. Process Explorer - 64비트 윈도우에서 32비트 프로세스의 덤프를 뜰 때 "Error writing dump file: Access is denied." 오류
13912정성태4/9/2025848닷넷: 2330. C# - 실행 시에 메서드 가로채기 (.NET 5 ~ .NET 8)파일 다운로드1
13911정성태4/8/20251075오류 유형: 949. WinDbg - .NET Core/5+ 응용 프로그램 디버깅 시 sos 확장을 자동으로 로드하지 못하는 문제
13910정성태4/8/20251240디버깅 기술: 219. WinDbg - 명령어 내에서 환경 변수 사용법
13909정성태4/7/20251710닷넷: 2329. C# - 실행 시에 메서드 가로채기 (.NET Framework 4.8)파일 다운로드1
13908정성태4/2/20252121닷넷: 2328. C# - MailKit: SMTP, POP3, IMAP 지원 라이브러리
13907정성태3/29/20251904VS.NET IDE: 198. (OneDrive, Dropbox 등의 공유 디렉터리에 있는) C# 프로젝트의 출력 경로 변경하기
13906정성태3/27/20252157닷넷: 2327. C# - 초기화되지 않은 메모리에 접근하는 버그?파일 다운로드1
13905정성태3/26/20252191Windows: 281. C++ - Windows / Critical Section의 안정화를 위해 도입된 "Keyed Event"파일 다운로드1
13904정성태3/25/20251879디버깅 기술: 218. Windbg로 살펴보는 Win32 Critical Section파일 다운로드1
13903정성태3/24/20251508VS.NET IDE: 197. (OneDrive, Dropbox 등의 공유 디렉터리에 있는) C++ 프로젝트의 출력 경로 변경하기
13902정성태3/24/20251719개발 환경 구성: 742. Oracle - 테스트용 hr 계정 및 데이터 생성파일 다운로드1
13901정성태3/9/20252097Windows: 280. Hyper-V의 3가지 Thread Scheduler (Classic, Core, Root)
13900정성태3/8/20252331스크립트: 72. 파이썬 - SQLAlchemy + oracledb 연동
13899정성태3/7/20251790스크립트: 71. 파이썬 - asyncio의 ContextVar 전달
13898정성태3/5/20252109오류 유형: 948. Visual Studio - Proxy Authentication Required: dotnetfeed.blob.core.windows.net
13897정성태3/5/20252347닷넷: 2326. C# - PowerShell과 연동하는 방법 (두 번째 이야기)파일 다운로드1
13896정성태3/5/20252162Windows: 279. Hyper-V Manager - VM 목록의 CPU Usage 항목이 항상 0%로 나오는 문제
13895정성태3/4/20252205Linux: 117. eBPF / bpf2go - Map에 추가된 요소의 개수를 확인하는 방법
13894정성태2/28/20252233Linux: 116. eBPF / bpf2go - BTF Style Maps 정의 구문과 데이터 정렬 문제
13893정성태2/27/20252180Linux: 115. eBPF (bpf2go) - ARRAY / HASH map 기본 사용법
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...