Java
[Java] Charset과 문자 인코딩
jngsngjn
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 서로 호환 안 됨