[Java] 문자형과 유니코드
문자형 char
문자형도 ‘char’ 한 가지 자료형밖에 없다. 문자를 저장하기 위한 변수를 선언할 때 사용되며, char타입의 변수는 단 하나의 문자만을 저장할 수 있다.
아래의 문장 타입은 char타입의 변수 ch를 선언하고, 문자 ‘A’로 초기화한다.
char ch = 'A'; // 문자 'A'를 char타입의 변수 ch에 저장
위 문장은 변수에 ‘문자’가 저장되는 것 같지만, 사실은 문자가 아닌 ‘문자의 유니코드(정수)’가 저장된다. 컴퓨터는 숫자밖에 모르기 때문에 모든 데이터를 숫자로 변환하여 저장하는 것이다.
문자 ‘A’의 유니코드는 65이므로, 변수 ch에는 65가 저장된다.
✅ char타입의 표현방식
char 타입의 크기는 2byte(=16bit)이므로, 16자리의 2진수로 표현할 수 있는 정수의 개수인 65536개(=2^16)의 코드를 사용할 수 있으며, char형변수는 이 범위 내의 코드 중 하나를 저장할 수 있다.
→ 예를들어 ‘A’를 저장하면, 아래와 같이 2진수 ‘0000 0000 0100 00001’(10진수 65)로 저장된다.
char타입의 변수에는 문자가 아닌 ‘문자의 유니코드(정수)’가 저장되고 표현형식 역시 정수형과 동일하다.
다만, 정수형과 달리 음수를 나타낼 필요가 없으므로 표현할 수 있는 값에 범위가 다르다.
📌 16비트로 표현할 수 있는 정수의 개수 : 2^16개(65536개)
short타입의 표현범위 : -2^15 ~ 2^15-1 (-32768~32767)
char타입의 표현 범위 : 0 ~ 2^16-1 (0 ~ 65535)
다음과 같이 변수 ch와 s에 ‘A’와 65를 저장하면, 둘 다 2진수로 똑같은 값이 저장된다.
컴퓨터는 모든 값을 0과 1로 바꾸어 저장하기 때문이다.
char ch = 'A'; // char ch = 65;
short s = 65;
하지만 두 변수를 출력하면 결과가 다르다.
이는 println()이 변수의 타입이 정수형이면 변수에 저장된 값을 10진수로 해석하여 출력하고,
문자형이면 저장된 숫자에 해당하는 유니코드를 출력하기 때문이다.
System.out.println(ch); // A가 출력됨.
System.out.println(s); //65가 출력됨.
✅ 인코딩과 디코딩(encoding & decoding)
컴퓨터가 숫자밖에 모르기 때문에 문자가 숫자로 변환되어 저장된다는 것은 알게 되었다.
그러면 어떤 기준에 의해서 변환하는 것일까?
문자 유니코드
A | 65 |
B | 66 |
C | 67 |
… | … |
위 표를 보면 문자 ‘A’의 유니코드가 65인 것을 알 수 있다. 그래서 문자 ‘A’를 유니코드로 인코딩하면 65가 되는 것이다. 역으로 65를 유니코드로 디코딩하면 문자 ‘A’가 된다
📌
문자를 코드로 변환하는 것을 ‘문자 인코딩(encoding)’ = A → 65
코드를 문자로 변환하는 것을 ‘문자 디코딩(decoding)’ = 65 → A
문자를 저장할 때는 인코딩을 해서 숫자로 변환해서 저장하고, 저장된 문자를 읽어올 때는 디코딩을 해서 숫자를 원래 문자로 되돌려야 한다.
✅ 아스키(ASCII)
‘ASCII’는 ‘American Standard Code for Information Interchange’의 약어로 정보 교환을 위한 미국 표준 코드라는 뜻이다. 아스키는 128개(=2^7)의 문자 집합(character set)을 제공하는 7 bit부호로, 처음 32개의 문자는 인쇄와 전송 제어용으로 사용되는 ‘제어문자’로 출력할 수 없고 마지막 문자(DEL)를 제외한 33번째 이후의 문자들은 출력할 수 있는 문자들로, 기호와 숫자, 영대소문자로 이루어져 있다.
아스키는 숫자 ‘0~9’, 영문자 ‘A~Z’와 ‘a~z’가 연속적으로 배치되어 있다는 특징이 있으며, 이러한 특징은 프로그래밍에서 유용하게 활용된다.
✅ 확장 아스키(Extended ASCII)와 한글
일반적으로 데이터는 byte단위로 다뤄지는데 아스키는 7 bit이므로 1 bit가 남는다. 이 남는 공간을 활용해서 문자를 추가로 정의한 것이 ‘확장 아스키’이다.
확장 아스키에 추가된 128개의 문자는 여러 국가와 기업에서 서로의 필요에 따라서 다르게 정의해서 사용된다. ISO(국제표준화기구)에서 확장 아스키 표준을 몇 가지 발표했는데 대표적인 것이 ‘ISO 8859-1’이다.
이는 서유럽에서 일반적으로 사용하는 문자들을 포함한다.
확장 아스키로도 표현할 수 있는 문자의 개수가 255개뿐이므로 한글을 표현하기에는 턱없이 부족하다.
한글을 표현하는 방법은 조합형과 완성형이 존재한다. 현재 조합형을 사용되지 않고 ‘완성형(KSC 5601)’에 없는 잘 안 쓰이는 8822글자를 추가한 ‘확장 완성형(CP 949)’이 사용되는데, 이것이 한글 윈도우에서 사용하는 문자 인코딩이다. 한글 윈도우에서 작성된 문자는 기본적으로 ‘CP 949(확장 완성형)’로 인코딩 되어 저장된다.
✅ 코드 페이지(code page, cp)
PC를 사용하는 지역이나 국가에 따라 여러 버전의 ‘확장 아스키’가 필요했다. IBM은 이들을 ‘코드페이지(code page)’라고 하고, 각 코드 페이지에 ‘CP XXX’와 같은 형식으로 명명했다.
한글 윈도우는 ‘CP 949’를, 영문 윈도우는 ‘CP 437’을 사용한다.
✅ 유니코드(Unicode)
컴퓨터 간의 문서교환이 활발해지기 시작하자 서로 다른 문자 인코딩을 사용하는 컴퓨터간의 문서교환에 어려움을 겪게 되었다. 이러한 어려움을 해소하기 위해 전 세계의 모든 문자를 하나의 통일된 문자집합으로 표현한 것이 ‘유니코드’이다.
2 byte로 표현하려 했으나 부족해서 21 bit(약 200만 문자)로 확장되었다. 새로 추가된 문자들을 보충문자(supplementary character)라고 한다. 이 문자들을 표현하기 위해서 char타입이 아닌 int타입을 사용해야 한다.
유니코드에 포함시키고자 하는 문자들의 집합을 정의하였는데, 이것을 유니코드 문자셋(또는 캐릭터 셋, character set)이라고 한다.
이 문자 셋에 번호를 붙인 것이 유니코드 인코딩이다. 유니코드 인코딩에는 UTF-8, UTF-16, UTF-32등 여러 가지 종류가 있는데 자바에서는 UTF-16을 사용한다.
📌
UTF-16은 모든 문자를 2byte의 고정크기로 표현
UTF-8은 하나의 문자를 1~4 byte의 가변크기로 표현
두 인코딩 모두 처음 128문자가 아스키와 동일하다. 아스키를 그대로 포함하고 있다.
⭐UTF-8, UTF-16
모든 문자의 크기가 동일한 UTF-16이 문자를 다루기는 편리하지만,
1 byte로 표현할 수 있는 영어와 숫자가 2 byte로 표현되므로 문서의 크기가 커진다는 단점이 있다.
UTF-8에서 영문과 숫자는 1byte 그리고 한글은 3 byte로 표현되기 때문에 문서의 크기가 작지만
문자의 크기가 가변적이므로 다루기 어렵다는 단점이 있다.
인터넷에서는 전송속도가 중요하므로, 문서의 크기가 작을수록 유리하다. 그래서 UTF-8 인코딩으로 작성된 웹문서의 수가 빠르게 늘고 있다.
참고자료 -