유니코드와 문자 인코딩

유니코드는 전세계 모든 문자를 2바이트(+4비트)로 구성된 문자 인코딩 표준

  • 흔히 유니코드라고 부르는건 표준 그 자체를 말하는 것으로 문자 인코딩이 아니다
  • 유니코드의 문자 인코딩에는 UTF-8, UTF-16등 이 존재한다
  • ascii 의 경우 그 자체가 문자열 집합과 인코딩을 포함 하고있는 것
  • 유니코드 문자 라고 부르는거는 보통 유니코드 포인트 를 의미하거나
    코드 포인트 안에 포함된 문자 그 자체를 의미

문자 데이터 / 바이너리 데이터

  • 문자도 결국은 바이너리
  • 그러나 웬만한 프로그래밍 언어들에서는 둘을 구분하여 씀
  • 문자열은 다양한 인코딩이 존재하여 인코딩 마다 바이너리를 처리하는 것이 재각각임
  • 그래서 다루기 쉽게하기 위해서 바이너리의 문자 인코더를 추가하여 추가적인 API 를 구성하고 있음

문자 인코딩

예제는 java 이지만 다른 언어도 마찬가지

참고

String 객체

String 객체 생성을 통한 인코딩의 잘못된 예

String str = new String("안녕".getBytes("UTF-8"), "UTF-8");
  • 해당 코드는 정말 의미 없는 코드이다
    1. 안녕 이라는 글자의 UTF-8 로 인코딩된 byte[] 로 반환 받는다
    2. 그리고 String 객체는 UTF-8로 인코딩된 byte[]UTF-8 로 해석 하여 문자열 안녕 을 얻는다
  • 얼핏 봐서는 문자열 안녕UTF-8 로 인코딩 한다고 생각할 수 있지만
  • new String() 이 하는 건 어떤 것으로 인코딩 된 byte[] 문자열을 같은 인코딩으로 해석하여 올바르게 String 으로 불러올 수 있게 하는 것 뿐이다
String str = new String("안녕".getBytes("UTF-8"), "EUC-KR");
  • 그렇다고 둘을 다르게 설정한다고 의미 있어지는 것도 아니다
  • UTF-8 로 인코딩된 byte[]String 객체가 EUC-KR로 해석 하겠다는건데
  • 이러면 당연히 문자열이 깨지게 된다. 그래서 깨진 문자열 그대로 str 에 저장된다.
  • 당연하지만 잘못된 인코딩으로 원본 정보가 손실 되어 UTF-8 로 변환한다 해서 복원 할 수 없다

원래 용도

String str = new String(reader.readLine().getBytes("EUC-KR"), "EUC-KR");
  • InputStream 이나 기타 파일 I/O 객체를 통해 읽은 데이터에 인코딩을 결정하는데 쓰인다
  • 어떤 파일이 EUC-KR 인코딩 셋을 사용하여 그냥 읽을 경우 문자열이 깨지는데 이걸
  • EUC-KR로 읽고 StringEUC-KR 로 해석하여 str에 올바른 문자열이 저장되도록 한다

쓰기

outputStream.write("안녕".getBytes("UTF-8"));
  • 만약 outputStream 의 해당되는 프로그램의 인코딩 셋이 깨지는 경우
  • byte로 변환할때 해당 프로그램과 동일한 인코딩 셋을 적용해야 한다

유니코드 포인트

전세계 모든 유니코드 (149,878개) 를 하나의 특수코드로 표기한 것
https://en.wikipedia.org/wiki/List_of_Unicode_characters

  • 알려진것과 다르게 실제론 2바이트가 아닌 21 비트 즉 2바이트+4비트

표기법

  • U+AC00: 가, U+D7A3: 힣
    • 보통 코딩에서 한글인지 판단할 때 가~힣 까지의 문자인지 판단해야하는게
    • 바로 이 유니코드 포인트 규칙에 있음

Supplementary Planes

원래 유니코드 포인트는 2바이트로 즉 65535 까지 밖에 존재 할 수 없다
그래서 문자열을 확장하려고 만든 것

  • 추가적으로 4 비트를 확장하여
  • U+10000 ~ U+10FFFF 까지의 문자열 범위를 말한다

프로그래밍 에서

  • 보통은 유니코드 문자열을 UTF-16 형태로 유니코드 포인트를 메모리에 저장하여
  • 원하는 인코딩으로 바이너리를 쓰는 형태임
  • 대부분에 문자는 2바이트 자료형(Char)로 저장 할 수 있지만 Supplementary Planes의 존재 때문에 해당 범위에 해당하는 문자열은 4바이트 까지 확장할 필요가 있다

유니코드 이스케이프 시퀀스

특정 문자를 명시적으로 표현 할 수 없을때 16진수 형태로 표현하는 방법
종류: https://learn.microsoft.com/ko-kr/cpp/c-language/escape-sequences?view=msvc-170

  • 주로 문자열을 \uC11D이런 식으로 유니코드 포인트로 표기를 할 수 있는
    • 해당 문자는 이다
    • 유니코드 포인트 상에서는 U+C11D
  • \n, \t 등 이런 문자열도 포함이다
  • java 에서 소스코드 컴파일 시 유니코드가 포함된 문자열은 전부 이스케이프 처리된다