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분
정성태

... 121  122  123  124  125  126  127  128  129  130  131  [132]  133  134  135  ...
NoWriterDateCnt.TitleFile(s)
1755정성태9/22/201434134오류 유형: 241. Unity Web Player를 설치해도 여전히 설치하라는 화면이 나오는 경우 [4]
1754정성태9/22/201424502VC++: 80. 내 컴퓨터에서 C++ AMP 코드가 실행이 될까요? [1]
1753정성태9/22/201420482오류 유형: 240. Lync로 세미나 참여 시 소리만 들리지 않는 경우 [1]
1752정성태9/21/201440946Windows: 100. 윈도우 8 - RDP 연결을 이용해 VNC처럼 사용자 로그온 화면을 공유하는 방법 [5]
1751정성태9/20/201438834.NET Framework: 464. 프로세스 간 통신 시 소켓 필요 없이 간단하게 Pipe를 열어 통신하는 방법 [1]파일 다운로드1
1750정성태9/20/201423736.NET Framework: 463. PInvoke 호출을 이용한 비동기 파일 작업파일 다운로드1
1749정성태9/20/201423671.NET Framework: 462. 커널 객체를 위한 null DACL 생성 방법파일 다운로드1
1748정성태9/19/201425290개발 환경 구성: 238. [Synergy] 여러 컴퓨터에서 키보드, 마우스 공유
1747정성태9/19/201428333오류 유형: 239. psexec 실행 오류 - The system cannot find the file specified.
1746정성태9/18/201425970.NET Framework: 461. .NET EXE 파일을 닷넷 프레임워크 버전에 상관없이 실행할 수 있을까요? - 두 번째 이야기 [6]파일 다운로드1
1745정성태9/17/201422912개발 환경 구성: 237. 리눅스 Integration Services 버전 업그레이드 하는 방법 [1]
1744정성태9/17/201430934.NET Framework: 460. GetTickCount / GetTickCount64와 0x7FFE0000 주솟값 [4]파일 다운로드1
1743정성태9/16/201420894오류 유형: 238. 설치 오류 - Failed to get size of pseudo bundle
1742정성태8/27/201426855개발 환경 구성: 236. Hyper-V에 설치한 리눅스 VM의 VHD 크기 늘리는 방법 [2]
1741정성태8/26/201421229.NET Framework: 459. GetModuleHandleEx로 알아보는 .NET 메서드의 DLL 모듈 관계파일 다운로드1
1740정성태8/25/201432384.NET Framework: 458. 닷넷 GC가 순환 참조를 해제할 수 있을까요? [2]파일 다운로드1
1739정성태8/24/201426425.NET Framework: 457. 교착상태(Dead-lock) 해결 방법 - Lock Leveling [2]파일 다운로드1
1738정성태8/23/201421947.NET Framework: 456. C# - CAS를 이용한 Lock 래퍼 클래스파일 다운로드1
1737정성태8/20/201419657VS.NET IDE: 93. Visual Studio 2013 동기화 문제
1736정성태8/19/201425512VC++: 79. [부연] CAS Lock 알고리즘은 과연 빠른가? [2]파일 다운로드1
1735정성태8/19/201418114.NET Framework: 455. 닷넷 사용자 정의 예외 클래스의 최소 구현 코드 - 두 번째 이야기
1734정성태8/13/201419770오류 유형: 237. Windows Media Player cannot access the file. The file might be in use, you might not have access to the computer where the file is stored, or your proxy settings might not be correct.
1733정성태8/13/201426207.NET Framework: 454. EmptyWorkingSet Win32 API를 사용하는 C# 예제파일 다운로드1
1732정성태8/13/201434347Windows: 99. INetCache 폴더가 다르게 보이는 이유
1731정성태8/11/201426910개발 환경 구성: 235. 점(.)으로 시작하는 파일명을 탐색기에서 만드는 방법
1730정성태8/11/201422030개발 환경 구성: 234. Royal TS의 터미널(Terminal) 연결에서 한글이 깨지는 현상 해결 방법
... 121  122  123  124  125  126  127  128  129  130  131  [132]  133  134  135  ...