이번 글은 김영한 님의 실전 자바 - 고급 2편을 참고했습니다.
가끔 자바를 사용하다보면 분명 한글이 나와야 하는데 아래와 같이 한글이 전부 깨지는 경험을 해봤을 것이다.
늘 정확한 이유는 고민하지 않고 인터넷에서 'UTF-8 설정 하면 됩니다~, 필터에 뭐 걸어주면 됩니다~' 이렇게 해결만 하고 넘어갔었다.
이번 강의에서 문자 깨짐과 UTF-8, UTF-16, 아스키코드에 대해 설명하고 있어서 정확히 정리하고 넘어가려고 한다.
먼저 컴퓨터는 이진수(바이너리 데이터), 즉 0과 1을 통해서 데이터를 저장한다.
숫자 3 -> 11
숫자 4 -> 100
숫자 6 -> 110
이렇게 10진수의 수를 2진수로 변환해서 컴퓨터는 저장하는데 여기서 0과 1을 비트(bit)라고 정의한다.
8개의 bit가 모여서 1바이트(byte)를 이루게 된다.
(가끔 비트와 바이트를 헷갈리곤 하는데 bit는 3자, byte는 4자니 bit가 먼저 등장한다고 생각하면 외우기 쉽다.)
즉 1bit를 추가할 때마다 표현할 수 있는 숫자는 2배씩 늘어나게 된다.
숫자는 2진수로 변환해서 저장하는 것이 이해가 된다. 그러면 문자는 어떻게 이진수로 변환해서 저장할 수 있을까?
예를 들어 A라는 문자를 컴퓨터에 저장해야 한다면 어떻게 2진수로 표현하는 것이 맞을까?
이 문제를 해결하기 위해 초창기 과학자들은 '문자 집합'이라는 개념을 만들어서 사용하기 시작했다.
즉 A가 들어오면 숫자 65로 저장되어야 한다는 의미이고 이는 2진수로 변환돼서 컴퓨터 메모리에 저장되는 것이다.
그런데 각 컴퓨터 회사들이 독자적인 문자 집합을 정의해서 사용한다면 어떻게 될까???
서로 컴퓨터에 사용하는 문자 집합이 다르기 때문에 출력에 문제가 발생하게 될 수 있다.
예를 들어 A라는 컴퓨터 회사는 ㅁ을 121로 저장해 뒀는데 B라는 컴퓨터 회사는 ㅁ을 58로 저장했다고 하면 다른 문자가 출력되는 문제가 발생하게 된다.
public static void main(String[] args) {
byte[] bytes = "인딥".getBytes(Charset.forName("MS_949"));
String decoded = new String(bytes, StandardCharsets.US_ASCII);
System.out.println(decoded);
}
------------------------------------------------------------------------
출력 결과 : ����
위 간단한 예시에서도 인코딩과 디코딩이 호환되지 않아서 문제가 발생하게 된다.
모든 컴퓨터에서 호환이 되는 문자 집합이 필요하기에 ASCII(American Standard Code for Information Interchange)라는 표준 문자 집합이 1960년도에 개발이 되었다.
https://ko.wikipedia.org/wiki/ASCII
ASCII - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. 1972 프린터 사용 설명서에 개시된 아스키 코드 차트표 미국정보교환표준부호(영어: American Standard Code for Information Interchange), 또는 줄여서 ASCII( , 아스키)는 영문
ko.wikipedia.org
초기에는 주로 영문, 숫자, 특수문자 등 기본적인 문자만 표현하면 충분했기에 7비트를 이용해서 128가지 문자를 표현했다.
또한 한글을 표현하기 위해서 EUC-KR이나 MS949를 만들어서 이용하기 시작했다.
그런데 전 세계적으로 컴퓨터 인구가 늘어나면서 전 세계 문자를 다룰 수 있는 문자 집합이 필요해지기 시작했다.
전 세계 모든 문자들을 단일 문자로 표현하기 위해 유니코드라는 개념이 1991년에 최초 발표되었다.
UTF-16
16비트 기반으로 자주 사용하는 기본 다국어들은 2바이트로 표현, 그 외에는 4바이트로 표현해서 42억 가지를 표현할 수 있다.(유니코드의 범위는 이보다 훨씬 작다)
그러나 UTF-16의 문제는 ASCII와 호환되지 않기에 영문을 사용한다면 2바이트를 사용하기에 1바이트만 사용하는 ASCII보다 2배의 메모리를 더 사용하게 된다.
(초반에는 UTF-16이 인기었어서 자바도 언어 내부적으로 문자를 표현할 때 UTF-16을 사용한다. 그래서 자바의 char 타입이 2바이트를 사용한다.)
UTF-8
8비트 기반으로 가변 길이의 인코딩 방식이다. 1바이트 ~ 4바이트를 사용하며 ASCII와 호환이 가능하다.
UTF-16은 대부분의 기본 문자들이 2바이트로 표현되기에 특정 문자에 접근하거나 문자 수를 세는 작업이 상대적으로 간단하다. 반면에 UTF-8은 각 문자가 가변 길이로 인코딩 되기에 특정 작업에서 조금 더 복잡한 편이다.
하지만 ASCII와 호환되고 ASCII를 1바이트로 표현할 수 있기에 UTF-8의 인기는 빠르게 치솟았고 2008년 W3C 웹 표준에서도 UTF-8을 채택하기 시작했다.
(현대 웹사이트는 대부분 기본 인코딩으로 UTF-8을 사용한다)
정리하면 UTF-8은 ASCII 문자를 포함한 많은 서양 언어의 문자에 대해 1바이트를 사용하고, UTF-16은 2바이트를 사용하기에 영문 텍스트에는 UTF-8이 훨씬 효율적이다.
(참고로 웹에 있는 문서의 80%는 영문이라고 한다.)
김영한님 강의에서도 결론은 UTF-8을 사용하는 것을 추천하고 있다.
평소에 문자가 깨지면 UTF-8로 디코딩을 진행하는데 앞으로는 그 이유를 이해한 상태로 문자 깨짐에 대응할 수 있겠다는 생각이 든다.
'JAVA 강의(인프런)' 카테고리의 다른 글
객체지향 설계 (2) | 2023.12.06 |
---|---|
abstract(추상) & interface(인터페이스) (1) | 2023.12.06 |
다형성 (2) (0) | 2023.12.06 |
다형성(1) (2) | 2023.12.03 |