티스토리 뷰

아스키코드? 유니코드가 뭐지?

  • 컴퓨터가 처음 발명되었을 때 표현 가능한 문자는 128개였다. 이를 ASCII 코드라고 한다. 영어 알파벳과 통화를 포함한 여러 기호를 표현할 수 있었기에 미국을 중심으로 한 영어권에서는 사용하는데 아무 문제가 없었다.

  • 컴퓨터가 보다 대중화되면서 대부분의 서유럽 언어의 알파벳을 추가하여 256개의 문자를 표현할 수 있게 되었다. 이를 ISO-8859-1 코드라고 한다. 유명한 오픈 소스 서블릿 컨테이너인 Apache Tomcat의 기본 언어 코드가 바로 ISO-8859-1이다. 이 문제로 쿼리 스트링에 포함된 한글 문자열이 깨지는 것을 누구나 경험해봤을 것이다. 초창기 HTML의 표준 언어 코드였기 때문에 아직도 서유럽의 적지 않은 웹사이트들이 이 코드로 제공된다.

  • 초창기 컴퓨터 산업은 미국을 비롯한 서유럽이 이끌었기에 아무 문제 없었다. 문제는 그 외의 다른 언어를 사용하는 지역이다. 결국 독자적인 코드를 만들어 사용하게 된다. 한국의 경우 KSC5601-1987을 사용하였다.

  • Unicode(유니코드)는 파편화된 전세계의 언어 코드를 하나의 코드로 통일하기 위해 나왔다. 유니코드는 총 1,114,112개의 문자를 표현할 수 있다. Plane이라 불리는 17개의 영역이 각각 65536개의 문자를 표현할 수 있으며 이모티콘(Emoji) 또한 개별 유니코드 문자로 제공한다.

\uAC00이 뭐지?

  • 유니코드(와 모든 언어 코드)의 각 문자는 식별 가능한 Code Point라는 숫자를 가진다.(데이터베이스의 PK를 생각하면 된다.) 예를 들어 유니코드의 0번째 문자는 0번째 Code Point라고 부른다. 유니코드에서는 아래 형식으로 표현한다.
// 한글 문자인 '가'를 가리키는 유니코드의 Code Point 문자열이다.
U+AC00
  • 첫번째 문자 U는 이 문자열이 유니코드의 Code Point임을 알려준다. + 이후의 4개 문자는 Code Point를 16진수로 표현한 것이다. AC00은 44032를 의미하는 16진수이다.

  • 전세계가 모두 유니코드를 사용한다면 아무런 문제가 없을 것이다. 하지만 때때로 과거에 개발되어 운영 중인 시스템이나 프로토콜 등의 호환성 문제로 유니코드를 ASCII로 표현해야 하는 상황이 생길 수 있다. 이런 문자열을 Unicode Escape Sequence라고 부른다. 형식은 아래와 같다.
// 한글 문자인 '가'를 의미하는 Unicode Escape Sequence이다.
\uAC00

  • Java에서는 아래와 같이 Unicode 문자열과 Unicode Escape Sequence 문자열을 손쉽게 상호 변환할 수 있다. (StringEscapeUtils을 사용하기 위해서는 Apache Commons Lang, ObjectMapper를 사용하기 위해서는 Jackson 라이브러리가 필요하다.)
// Unicode Escape Sequence는 char 타입의 변수에 바로 저장할 수 있다.
char gaChar = '\uAC00';

// 문자의 최소값인 '\u0000'을 저장한다.
char charMin = Character.MIN_VALUE;

// 문자의 최대값인 '\uFFFF'를 저장한다.
char charMax = Character.MIN_VALUE;

// "\uAC00\uB098\uB2E4\uB77C\uB9C8\uBC14\uC0AC"를 출력한다.
StringEscapeUtils.escapeJava("가나다라마바사");

// "가나다라마바사"를 출력한다.
StringEscapeUtils.unescapeJava("\uAC00\uB098\uB2E4\uB77C\uB9C8\uBC14\uC0AC");

// Jackson 라이브러리 사용시 Unicode Escape Sequence로 표현된 JSON 문자열로 변환할 수 있다.
ObjectMapper mapper = new ObjectMapper();
mapper.getFactory().configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
  • 앞서 언급했듯이 유니코드는 1,114,112개의 문자를 표현할 수 있으며 Code Point 범위는 U+0000부터 U+10FFFF가 된다.

UTF-8은 뭐지?

  • UnicodeCode Point는 국제적인 표준 언어 코드를 설명하는 논리적 단위일 뿐이다. 같은 유니코드라도 실제로 컴퓨터에 어떻게 저장하느냐에 따라 여러가지 방식으로 나뉘어 진다. 이를 인코딩(Encoding) 또는 캐릭터셋(Charset)이라고 부르며 UTF-8, UTF-16 등 다양한 인코딩 방식이 존재한다. 인터넷 세계에서는 1999년 HTML4 표준이 등장한 이래 UTF-8을 표준 인코딩 방식으로 권장하고 있으며 오늘날 대부분의 텍스트는 UTF-8로 저장되고 있다. UTF-8 인코딩은 1개 문자를 Code Point에 따라 1~4 바이트로 가변적으로 저장하는 방식이다.

Java와 UTF-8

  • Java는 기본적으로 유니코드를 완벽히 지원하는 언어이며 내부적으로는 1개 문자를 UTF-16 인코딩으로 저장한다. 유니코드의 0번 플레인(U+0000부터 U+FFFF 코드포인트)까지는 1개 char 타입(2바이트)으로 표현하고 나머지 1~16번 플레인(U+10000부터 U+10FFFF 코드포인트)은 2개의 char 타입을 묶어(4바이트) 1개 문자로 표현한다. 예를 들어 U+20000 코드포인트는 2개의 char를 묶음으로 하여 \uD840\uDC00와 같이 UTF-16 인코딩으로 저장한다. 이와 같이 1개 유니코드 문자가 항상 1개의 char 타입으로 대응되지 않는다는 사실을 인지하고 있어야 한다. char 타입의 배열인 String 문자열 타입의 크기(length())가 유니코드 문자의 개수와 일치하지 않는 이유이다.

  • 위와 같이 Java는 내부적으로 UTF-16 인코딩으로 유니코드를 지원하지만 인터넷 세계에서는 UTF-8 인코딩을 표준으로 사용한다. 아래와 같이 String 문자열 타입을 UTF-8 형식으로 변환할 수 있다.
// "가나다" 문자열을 UTF-8 인코딩의 바이트 배열로 저장한다.
byte[] bytes = "가나다".getBytes(StandardCharsets.UTF_8);

// UTF-8 인코딩된 바이트 배열을 문자열로 저장한다.
String text = new String(bytes, StandardCharsets.UTF_8);

// 문자열을 UTF-8 인코딩된 파일로 저장한다. Apache Commons IO 라이브러리를 사용하였다.
FileUtils.writeStringToFile(new File("C:\\utf8.txt"), "가나다", StandardCharsets.UTF_8);

MySQL과 UTF-8

  • MySQL 5.5.3 이전 버전이 제공하는 utf8 인코딩은 Unicode의 0번 플레인(BMP: Basic Multilingual Plane)의 65536개의 문자만 수용할 수 있다. 가변형으로 문자 1개당 1~3바이트 공간을 차지한다. 대부분의 문자를 수용할 수 있지만 다른 플레인(1~16)에 속하는 일부 중국어 및 특수문자(Emoji)의 수용이 불가능하다.

  • MySQL 5.5.3부터 제공하는 utf8mb4 인코딩은 Unicode의 0~16번까지의 모든 플레인의 문자를 수용할 수 있다. utf8mb4utf8에 대한 완벽한 하위 호환성을 제공하며 어떠한 추가 공간도 차지하지 않는다.(0번 플레인 이후의 문자만 4바이트를 차지한다.) 따라서 UTF-8을 지원하는 테이블 및 컬럼은 반드시 utf8mb4로 인코딩되어야 한다. [관련 링크]

  • 테이블 생성시 아래와 같이 utf8mb4 인코딩을 지정할 수 있다.
CREATE TABLE some_table (
  ...
)
DEFAULT CHARACTER SET utf8mb4;
DEFAULT COLLATE utf8mb4_unicode_ci;

참고글

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함