ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] Charset과 문자 인코딩
    Java 2024. 11. 8. 21:41

    문자 집합

    1. ASCII

    • 오늘날 사용하는 많은 문자 집합의 기초가 되는 문자 집합
    • UTF-16을 제외한 대부분의 문자 집합에 호환됨
    • 한글 지원 X

    2. ISO_8859_1

    • ASCII + 서유럽 문자 추가
    • 한글 지원 X

    한글 문자 집합

    3. EUC-KR

    • 초창기 등장한 한글 문자 집합
    • ASCII + 자주 사용하는 한글
    • 2byte 한글

    4. MS949

    • 마이크로소프트가 EUC-KR을 확장하여 만든 문자 집합
    • 복잡한 한글 표현 가능 (쀍, 뷁, 삡 등)
    • 윈도우 시스템에서 계속 사용됨

    유니코드

    • 1990년대에 전 세계 모든 문자들을 단일 문자 세트로 표현할 수 있는 유니코드 표준이 등장함
    • UTF-16, UTF-8

    5. UTF-16

    • 영문을 2byte로 사용하고, ASCII와 호환되지 않는다는 단점으로 인해 현재는 잘 사용되지 않음
    • 자주 사용하는 기본 다국어들을 2byte로 표현

    6. UTF-8

    • 현재 가장 많이 사용되는 문자 집합
    • 1byte 영문, 3byte 한글, ASCII 호환

     

    public class EncodingMain1 {
    
        private static final Charset EUC_KR = Charset.forName("EUC-KR");
        private static final Charset MS_949 = Charset.forName("MS_949");
    
        public static void main(String[] args) {
            System.out.println("### ASCII 영문 처리 ###");
            encoding("A", US_ASCII);
            encoding("A", ISO_8859_1);
            encoding("A", EUC_KR);
            encoding("A", UTF_8);
            encoding("A", UTF_16BE); // 2byte
    
            printLine();
    
            System.out.println("### 한글 지원 ###");
            encoding("가", EUC_KR);
            encoding("가", MS_949);
            encoding("가", UTF_8); // 3byte
            encoding("A", UTF_16BE);
        }
    
        private static void encoding(String text, Charset charset) {
            byte[] bytes = text.getBytes(charset);
            System.out.printf("%s -> [%s] 인코딩 -> %s %sbyte\\n", text, charset, Arrays.toString(bytes), bytes.length);
        }
    }
    ### ASCII 영문 처리 ###
    A -> [US-ASCII] 인코딩 -> [65] 1byte
    A -> [ISO-8859-1] 인코딩 -> [65] 1byte
    A -> [EUC-KR] 인코딩 -> [65] 1byte
    A -> [UTF-8] 인코딩 -> [65] 1byte
    A -> [UTF-16BE] 인코딩 -> [0, 65] 2byte
    
    ==================================================================
    
    ### 한글 지원 ###
    가 -> [EUC-KR] 인코딩 -> [-80, -95] 2byte
    가 -> [x-windows-949] 인코딩 -> [-80, -95] 2byte
    가 -> [UTF-8] 인코딩 -> [-22, -80, -128] 3byte
    A -> [UTF-16BE] 인코딩 -> [0, 65] 2byte
    

    public class EncodingMain2 {
    
        private static final Charset EUC_KR = Charset.forName("EUC-KR");
        private static final Charset MS_949 = Charset.forName("MS_949");
    
        public static void main(String[] args) {
            System.out.println("### 영문 ASCII 인코딩 ###");
            test("A", US_ASCII, US_ASCII);
            test("A", US_ASCII, ISO_8859_1);
            test("A", US_ASCII, EUC_KR);
            test("A", US_ASCII, MS_949);
            test("A", US_ASCII, UTF_8);
            test("A", US_ASCII, UTF_16BE); // 실패
    
            printLine();
    
            System.out.println("### 한글 인코딩 (기본) ###");
            test("가", US_ASCII, US_ASCII); // 실패
            test("가", ISO_8859_1, ISO_8859_1); // 실패
            test("가", EUC_KR, EUC_KR);
            test("가", MS_949, MS_949);
            test("가", UTF_8, UTF_8);
            test("가", UTF_16BE, UTF_16BE);
    
            printLine();
    
            System.out.println("### 한글 인코딩 (복잡한 문자) ###");
            test("뷁", EUC_KR, EUC_KR); // 실패
            test("뷁", MS_949, MS_949);
            test("뷁", UTF_8, UTF_8);
            test("뷁", UTF_16BE, UTF_16BE);
    
            printLine();
    
            System.out.println("### 한글 인코딩 (디코딩이 다른 경우) ###");
            test("가", EUC_KR, MS_949);
            test("뷁", MS_949, EUC_KR); // 실패
            test("가", EUC_KR, UTF_8); // 실패
            test("가", MS_949, UTF_8); // 실패
            test("가", UTF_8, MS_949); // 실패
    
            printLine();
    
            System.out.println("### 영문 인코딩 (디코딩이 다른 경우) ###");
            test("A", EUC_KR, UTF_8);
            test("A", MS_949, UTF_8);
            test("A", UTF_8, MS_949);
            test("A", UTF_8, UTF_16BE); // 실패
        }
    
        private static void test(String text, Charset encodingCharset, Charset decodingCharset) {
            byte[] encoded = text.getBytes(encodingCharset);
            String decoded = new String(encoded, decodingCharset);
            System.out.printf("%s -> [%s] 인코딩 -> %s %sbyte -> [%s] 디코딩 -> %s\\n",
                    text, encodingCharset, Arrays.toString(encoded), encoded.length,
                    decodingCharset, decoded);
        }
    }
    ### 영문 ASCII 인코딩 ###
    A -> [US-ASCII] 인코딩 -> [65] 1byte -> [US-ASCII] 디코딩 -> A
    A -> [US-ASCII] 인코딩 -> [65] 1byte -> [ISO-8859-1] 디코딩 -> A
    A -> [US-ASCII] 인코딩 -> [65] 1byte -> [EUC-KR] 디코딩 -> A
    A -> [US-ASCII] 인코딩 -> [65] 1byte -> [x-windows-949] 디코딩 -> A
    A -> [US-ASCII] 인코딩 -> [65] 1byte -> [UTF-8] 디코딩 -> A
    A -> [US-ASCII] 인코딩 -> [65] 1byte -> [UTF-16BE] 디코딩 -> �
    
    ==================================================================
    
    ### 한글 인코딩 (기본) ###
    가 -> [US-ASCII] 인코딩 -> [63] 1byte -> [US-ASCII] 디코딩 -> ?
    가 -> [ISO-8859-1] 인코딩 -> [63] 1byte -> [ISO-8859-1] 디코딩 -> ?
    가 -> [EUC-KR] 인코딩 -> [-80, -95] 2byte -> [EUC-KR] 디코딩 -> 가
    가 -> [x-windows-949] 인코딩 -> [-80, -95] 2byte -> [x-windows-949] 디코딩 -> 가
    가 -> [UTF-8] 인코딩 -> [-22, -80, -128] 3byte -> [UTF-8] 디코딩 -> 가
    가 -> [UTF-16BE] 인코딩 -> [-84, 0] 2byte -> [UTF-16BE] 디코딩 -> 가
    
    ==================================================================
    
    ### 한글 인코딩 (복잡한 문자) ###
    뷁 -> [EUC-KR] 인코딩 -> [63] 1byte -> [EUC-KR] 디코딩 -> ?
    뷁 -> [x-windows-949] 인코딩 -> [-108, -18] 2byte -> [x-windows-949] 디코딩 -> 뷁
    뷁 -> [UTF-8] 인코딩 -> [-21, -73, -127] 3byte -> [UTF-8] 디코딩 -> 뷁
    뷁 -> [UTF-16BE] 인코딩 -> [-67, -63] 2byte -> [UTF-16BE] 디코딩 -> 뷁
    
    ==================================================================
    
    ### 한글 인코딩 (디코딩이 다른 경우) ###
    가 -> [EUC-KR] 인코딩 -> [-80, -95] 2byte -> [x-windows-949] 디코딩 -> 가
    뷁 -> [x-windows-949] 인코딩 -> [-108, -18] 2byte -> [EUC-KR] 디코딩 -> ��
    가 -> [EUC-KR] 인코딩 -> [-80, -95] 2byte -> [UTF-8] 디코딩 -> ��
    가 -> [x-windows-949] 인코딩 -> [-80, -95] 2byte -> [UTF-8] 디코딩 -> ��
    가 -> [UTF-8] 인코딩 -> [-22, -80, -128] 3byte -> [x-windows-949] 디코딩 -> 媛�
    
    ==================================================================
    
    ### 영문 인코딩 (디코딩이 다른 경우) ###
    A -> [EUC-KR] 인코딩 -> [65] 1byte -> [UTF-8] 디코딩 -> A
    A -> [x-windows-949] 인코딩 -> [65] 1byte -> [UTF-8] 디코딩 -> A
    A -> [UTF-8] 인코딩 -> [65] 1byte -> [x-windows-949] 디코딩 -> A
    A -> [UTF-8] 인코딩 -> [65] 1byte -> [UTF-16BE] 디코딩 -> �
    

    • getBytes() 호출 시 매개변수로 Charset을 제공하는 게 좋다. 매개변수를 제공하지 않으면 시스템 기본 Charset으로 인코딩 된다.
    • 한글을 ASCII 등 한글을 지원하지 않는 문지 집합으로 인코딩 시 인코딩 할 수 없기 때문에 ?로 인코딩 된다.

    한글이 깨지는 주요 원인

    • EUC-KR or MS949  UTF-8 서로 호환 안 됨
    • EUC-KR or MS949 or UTF-8  ISO-8859-1 서로 호환 안 됨

    'Java' 카테고리의 다른 글

    [Java] 리플렉션(Reflection)에 대해서  (1) 2025.01.17
    [Java] I/O 정리  (1) 2024.11.09
    [Java] 다형성 (Polymorphism)  (0) 2024.11.07
    [Java] Dump File에 대해서  (0) 2024.10.31
    [Java] Native Resource와 native 예약어  (1) 2024.10.30