[완료] UTF-16LE 문자열의 길이를 알아내는 방법은?

poplinux의 이미지

EUC-KR 을 UTF-16 으로 변환하는 프로그램을 iconv 를 사용해서 짜고 있습니다.

물론 알고 계시겠지만, iconv() 함수의 리턴값이 전체 문자열의 길이를 리턴해 준다는 보장이 없습니다. 그래서 그 부분을 사용하기는 어렵습니다.

다음과 같은 EUC-KR 문자열을 UTF-16으로 변환하면

string = "abcd 나는 당신을 사랑합니다. cfg 123456"

strlen() 함수를 사용해서 길이를 알아보게 될 경우 1 로 나옵니다. 아마도 UTF-16 으로 인코딩 된 문자열 중간에 strlen() 에서 NULL 문자로 인식하는 부분이 있나 봅니다.

혹시나 해서

EUC-KR 을 UTF-8로 바꾸었을 경우엔 정상적인 길이가 나옵니다.

문자열의 길이가 필요한 이유는 문자열 앞에 헤더를 붙이는데 그 헤더에 문자열의 길이가 들어가기 때문입니다.

어떻게 해야 변환된 문자열의 총길이를 알아낼수 있을까요?

bushi의 이미지

size_t iconv(iconv_t cd,
                     char **inbuf, size_t *inbytesleft,
                     char **outbuf, size_t *outbytesleft);

아시다시피 outbytesleft 는 output buffer 의 남은 공간입니다.
변환 후 남은 공간의 크기를 알 수 있다면, 사용된 공간의 크기를 계산할 수 있지 않겠습니까 ?
"문자열의 길이" 라는 게 정말로 의미심장하긴 합니다만.
wish의 이미지

씨에서 문자열은 NULL 문자열입니다.

예를 들어 "a" 라는 문자열은 65 00 요렇게 되죠.

그래서 길이를 처리할 때 처음부터 00 까지 몇 바이트인가를 셉니다.

그런데 utf-16 인코딩은 NULL 문자열과 호환이 안됩니다.

왜냐하면 모든 문자를 16비트로 표현하는데, ascii 부분을 포함한 0~255 사이에 있는 문자를 표현할때 전부 00 이 앞에 붙어 버립니다.

utf-16le 이면 little endian 이므로..

string = "abcd 어쩌구~"

65 00 66 00 ....

이렇게 나가므로, strlen(string) 하면 1이 리턴 되는 것입니다. 널 문자까지 1바이트 밖에 없으니까요.

utf-8의 경우 문자열을 처음부터 씨 문자열과 호환을 염두에 두고 만든 것이므로 NULL 문자열과 호환이 됩니다. 널 문자를 제외한 어떤 문자도 00 이라는 8비트 시퀀스를 포함하지 않습니다. 그래서 제대로 된 값이 나오는 것입니다.

해결책은 유니코드 문자열을 쓰시고 wcslen 함수를 쓰는 것입니다.

char 대신에 wchar_t, "" 대신에 L"" 을 쓰시고 wcslen() 함수를 이용해 보세요. 여기서 언급한 것은 대충 언급한 것이니, 자세한 것은 unicode FAQ 등을 보시고, 임시 방편으로 때우시려면 그냥 (sizeof(string) - 2) / 2 하시면 문자열 길이가 나올 것입니다. utf-16 에서 널문자 크기는 2바이트 이니까요. 이 경우는 각 문자가 BMP 영역 내에 있는 경우에만 해당 됩니다. 이상한 옛날 한문 같이 BMP 이후에 있는 문자는 아마 4바이트로 인코딩 되니까요.

Necromancer의 이미지

UTF16이면 1문자 = 2byte입니다.

직접 만드시겠다면 입력 문자열 포인터를 unsigned short *포인터로 바꾼뒤에 0이 나올때까지의 수를 세면 됩니다.
그리고 바이트단위 길이를 잰다면 0이 나오기 전까지의 unsigned short의 갯수 *2하면 되고요.
문자수만 센다면 중간에 대행코드 나오면 unsigned short 두개가 한문자를 이루니 그걸 처리해야합니다.

Written By the Black Knight of Destruction

Written By the Black Knight of Destruction

wish의 이미지

UTF16의 문자가 항상 2바이트 인 것은 아닙니다.

http://en.wikipedia.org/wiki/UTF-16

Examples 부분만 보셔도 언제나 2바이트가 아니란 것을 아실 수 있을 겁니다.

어떤 부분에서 2바이트가 아닌 4바이트가 되는지는 위 링크의 Encoding of characters outside the BMP 부분을 보시면 됩니다~

poplinux의 이미지

감사합니다.

========================
조직 : E.L.D(Embedded Linux Developer/Designer)
블로그 : poplinux@tistory.com
카페 : cafe.naver.com/poplinux

임베디드 리눅스 관련 프리렌서 지향

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.