백만년 만에 글. 너무 글을 안써서 오랜만에 생각나서 써 봄. ㅋ


Java에서 제공하는 기본적인 Reader계열에서는 UTF-8의 BOM을 제대로 처리하지 못합니다. 그렇기 때문에 BOM이 있는 UTF-8 stream을 Reader로 넣으면, String의 제일 앞글자에 0xfeff 가 들어 오는 문제가 생깁니다.


"UTF-8의 BOM을 제대로 처리 못하는 Java의 문제가 아니냐?" 고 물을 수 있겠지만은, Unicode 표준에는 UTF-8에 대해서는 BOM을 적지 않도록 권고(neither required nor recommended)하고 있습니다. 그런데 MS Windows 계열에서 만들어진 일부 문서에서는 BOM을 포함하는 경우가 종종있습니다.


이를 해결할 수 있는 방법은, 


 1. BOM에 대한 정보를 inputStream에서 미리 읽어 버리고, BOM 이후부터 Reader에서 읽도록 처리하는 방법

 2. 얻어진 String에서 tmp = tmp.replace("\uFEFF", ""); 와 같은 방법으로 0xfeff 무시하기

 3. 각종 외부 라이브러리를 이용해서 처리 하기


입니다.


저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
  1. 제미니 2014.07.08 13:41 신고

    이 글 덕분에 문제를 해결했습니다. 감사합니다!

내용에 대해서 책임지지 않습니다. ㅋㅋ


Unicode provides a unique number for every character,
no matter what the platform,
no matter what the program,
no matter what the language.

http://www.unicode.org/standard/WhatIsUnicode.html


위에 설명되어 있는대로다.




유니코드란?

unicode는 모든 문자에 index를 줘 놓은 것이다. 더 이상도 아니고, 더 이하도 아니다.
이 index를 code point라고 부르는데, 그냥 index라고 칭하도록 하자.

'A'라는 글자는 0x0041 이라는 index를 가진다.
'a'라는 글자는 0x0061 이라는 index를 가진다.
'가'라는 글자는 0xac00 이라는 index를 가진다.
( 더 많은 글자와 index를 보려면 http://www.unicode.org/charts/ 를 참고하자 )




표현방법

저렇게 정해져 있는 index를 표시하는 방법에는 UTF와 UCS두가지 종류가 있다.
( UTF - Unicode Transformation Format ,    UCS - Universal Character Set )

UCS
UCS는 몇바이트로 index를 표현할 수 있느냐를 나타낸다.
즉 UCS-2는 2byte로 index를 나타낼꺼고 UCS-4는 4byte를 이용해서 index를 나타낼거라는거다.

UTF
UTF는 몇 비트단위로사용해서 index를 나타낼것인가를 말한다.
UTF-8은 8bit씩 늘려가며 index를 나타낼꺼라는거고,
UTF-16은 16bit씩 index를 나타낼꺼고, UTF-32는 32bit씩 index를 나타낼꺼라는거다.
( 실상 UTF-16과 UCS-2는 같다고 볼 수 있다. 마찬가지로 UTF-32와 UCS-4도 마찬가지다.  하지만 unicode 3.1에 오면서 달라 졌다. )





UTF-16

원래 처음에 unicode의 index는 2byte로 나타낼 수 있었다.
그랬는데, unicode 가 버젼업되어 4.0이 나왔을때에는 0x10FFFF 까지의 index가 생겼다.

처음에는 UTF-16으로 모든 문자를 나타낼 수 있었으나,
( 2byte로 표현할 수 있는 index를 가진 문자 목록을 BMP Basic Multilingual Plane 라고 부른다. )
유니코드 4.0이 나오면서, 2byte로는 0x10FFFF 같은 값을 가리킬 수 없게 되었다.

그래서 UTF-16으로는 BMP에 있는 문자들은 2byte로 처리하고, 
BMP보다 더 높은 index를 가지는 놈들은 4byte로 처리 한다.
문자 index 0x0000 부터 0xFFFF 까지는 2byte로 처리 하고
문자 index 0x10000 부터 0x1FFFF 까지는 4byte로 처리 된다.





UTF-32

UTF-32는 기본적으로 4byte를 사용하기 때문에, 위와 같은 짓을 하지 않아도 된다.





UTF-8

영어권에 있는 사람들은 UTF-16을 쓰면 손해다.
모든 영어는 1byte만 있으면 256개를 표현할 수 있으므로, 모든 문자를 넣을 수 있기 때문이다.

그래서 나온게 UTF-8이다.
영어권은 1byte로 표현하고, 그것보다 높은 index를 가지는것은 2byte 혹은 3byte 혹은 4byte ..
요렇게 늘려 가면서 쓰도록 되어 있다.





서로간의 변환

UTF-8, UTF-16, UTF-32, UCS-2, UCS-4 는
모두 unicode의 문자 index를 나타내기 위한 방법이기 때문에,
서로간의 변환은 당연히 잘 된다. ( UCS-2는 한계를 가지고 있다. )




글자처리

우리가 글자 "가"를 쓴다고 해 보자.  글자 "가"는 1글자이다.
그러므로 "가"를 나타내는 index가 있다. 물론 "나"를 나타내는 index도 있다.

한글로 표현할 수 있는 글자는 매우 많다.
그 많은 글자 모두에게 index를 줄 수가 없다.

현재 사용하고 있는 모든 글자에 index를 준다고 해도,
시간이 지나서 새로운 글자가 추가 되어 index가 모자르게 된다면 어떻게 할것인가?

그래서 유니코드는 완전한 글자를 제공해 주기도 하지만,
글자를 조립할 수 있도록 조립가능한 글자를 제공해 준다.

다시 "가"를 쓴다고 해 보다.
"가"라는 글자는 1개이지만, 실제로는 초성 "ㄱ"과 중성"ㅏ" 가 합쳐져서 만들어진 글자이다.

그러므로 "가"를 표현하는 방법은 완성된 글자 "가"0xAC00가 될 수도 있고,
초성"ㄱ"과 중성"ㅏ"를 조립한 "가"0x1100,0x1161 로 나타낼 수도 있다.
( 초성 "ㄱ"은 0x1100 - HANGUL CHOSEONG KIYEOK )
( 중성 "ㅏ"는 0x1161 - HANGUL JUNGSEON A )

이를 조합할 수 있게 해 주는 index는 1100 부터 있다.
( Hangul Jamo - Korean combining alphabet - http://www.unicode.org/charts/PDF/U1100.pdf )


이는 비단 한글뿐만 아니라,
일본어 역시 완성된 글자가 있기도 하고, 조합할 수 있게도 되어 있다.

영어 역시 그렇다. 영어에서 무슨 글자를 조합하냐 라고 말하겠지만, 
이력서를 나타내는 Resume 의 경우에는 e 와 ' 의 조합으로 이루어 질 수도 있다.


신고
크리에이티브 커먼즈 라이선스
Creative Commons License
  1. 지민아빠 2008.02.28 09:47 신고

    맞는 말이구만 왜 내용에 책임을 안져요! ㅋㅋ

    • Chan 2008.02.28 09:59 신고

      유니코드랑 UTF관련은 머릿속에 정리 된것을 열심히 읽었는데,
      그 뒤에 글인 CP949 관련 글은 아직 머릿속에 확립이 안되어서.. ㅋㅋㅋ.
      CP949에 "책임질수 없음" 넣어 놓고, 유니코드 글에도 걍 넣었어요.. ㅋㅋ

    • 지민아빠 2008.03.11 12:05 신고

      아참. 펄에서 사용되는 이름이랑 자바에서 사용되는 이름이랑 약간 달라요. CP949, MS949, EUC-KR 의미가 약간 다름.

  2. sanaigon 2009.01.09 09:49 신고

    퍼가용ㅋ

  3. finebe 2009.04.24 14:11 신고

    퍼가요~^^; 공개글로 원치않으시면 말씀해주세요

    • Chan 2009.04.24 18:53 신고

      출처만 밝힌다면 상관없습니다. ㅋㅋ

  4. 2009.07.24 15:40

    비밀댓글입니다

  5. 킴킴 2014.01.20 17:13 신고

    퍼갈게요 ㅎㅎ

  6. carrot1st 2015.07.27 10:39 신고

    퍼갑니다 잘보겠습니다~

  7. 어벙이 2015.08.17 12:41 신고

    퍼갈게요..~~ ^^ 좋은 내용 잘 보고 갑니다..

  8. Gizmo_j 2016.07.28 09:33 신고

    잘보고 갑니다~
    퍼갈게요~~ ^^;

  9. 뚝딱콩망치 2017.03.26 16:51 신고

    내용 참고해서 글써두 될까요 ㅠㅠ 출처는 꼭 남기겠습니다!

java.lang.Character

  • JDK 1.4 : Character information is based on the Unicode Standard, version 3.0.
  • JDK 5.0 : Character information is based on the Unicode Standard, version 4.0. 

Java에서 char 은 16bit 고정 길이를 가지도록 되어 있다.

하지만 unicode 의 값 중에는 U+0000 ~ U+FFFF 를 넘어서는 값도 있기 때문에 이에 대한 처리가 문제가 된다.

1

JDK 1.4의 api document 중에서 Character 에 관한 문서를 확인해 보고

( http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Character.html  )

JDK 5.0의 api document 중에서 Character 에 관한 문서를 확인해 보면 서로 틀린것을 알 수 있다.

( http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Character.html )



JDK 5.0에서는 Unicode Character Representations 항목이 추가 된 것을 알 수 있다.

  1. 유니코드의 표준이 16비트 이상도 표현하도록 변경되었다.
  2. 현재는 U+0000 부터 U+10FFFF 까지 정의되어 있다.
  3. U+0000 부터 U+FFFF 까지는 Basic Multiingual Plane(BMP)를 참고한다.
  4. U+FFFF 보다 큰것들은 supplementary cahcaters가 있어야 한다.
  5. Java 2 에서는 UTF-16을 사용한다.
  6. supplementary chacters는 char 두개로 이루어 진다.
  7. 첫번째 char은 U+D800 ~ UDBFF를 , 두번째 char은 U+DC00~U+DFFF 까지의 범위를 가진다.
  8. char은 BMP나 UTF-16인코딩만을 가리킬 수 있다. 
    1. 그러므로 char를 사용하는 메소드를 쓸때에는, supplementary char에 대해서는 메소드를 호출 하면 잘못된 값이 나올 수 있다.
    2. 예)  Character.isLetter('\uD840') 를 사용하면 false로 return 된다.
  9. int는 supplementary code point 도 가리킬 수 있다. 
    1. 하위 21bit 는 Unicode값을 가리키고, 상위 11비트는 항상 0로 채워져 있다.
    2. 21bit인 이유는 현재 Unicode 가  U+10FFFF 까지 가리킬 수 있기 때문이다. ( U+10FFFF를 2진수로 변경하면 총 21bit 만을 차지하게 된다. )
    3.  그러므로 int를 사용하는 char 관련 메소드를 사용할때에는 supplementary char에 대해서는 제대로 된 응답이 반환된다.
      1. 예)  Character.isLetter(0x2F81A) 를 사용하면 true로 return 된다.

신고
크리에이티브 커먼즈 라이선스
Creative Commons License

+ Recent posts