UTF-8로 인코딩된 텍스트 파일에서 한글 읽어올때 문제가 발생합니다.
글쓴이: noblepylon / 작성시간: 금, 2008/06/13 - 2:38오후
오늘 벌써 세번째 질문입니다-_-;
유니코드로 프로그램을 하나 짜고 있습니다.
UTF-8인코딩으로 된 텍스트파일에서 한글을 읽어와야 하는데 자꾸만 엉뚱한 값이 들어가서 골치가 아프네요.
분명히 화면에서 직접 입력을 받으면 제대로 동작을 합니다.
wchar_t c; setlocale(LC_CTYPE, ""); wprintf(L"c 입력: "); wscanf(L"%lc", &c); wprintf(L"0x%X: %lc\n", c, c); return 0;
c 입력: 갉 // 입력 0xAC09: 갉 // 출력
그런데 이것을 파일입력으로 바꾸면 c에 엉뚱한 값이 들어가버리는군요.
wchar_t c; setlocale(LC_CTYPE, ""); FILE* fin = fopen("input.txt", "r, ccs=UTF-8"); fwscanf(fin, L"%lc", &c); wprintf(L"0x%X: %lc\n", c, c); return 0;
갉 // input.txt 0x5A9B: 媛 // 출력
c에 AC09('갉')가 들어가지 않고 5A9B('媛')가 들어가는지 당최 이유를 알 수 없군요.
이것때문에 현재 더 이상 진행이 되지 않고 있습니다. OTL
ps. input.txt는 분명히 UTF-8로 만들어졌습니다.
Forums:
BOM
byte order mark.
Hello World.
wprintf() 등등은 UTF16
wprintf() 등등은 UTF16 처리할때 씁니다.
그리고 UTF8이면 한글은 3바이트가 됩니다. UTF8-UTF16 변환작업이 선행되어야 할 거 같네요.
Written By the Black Knight of Destruction
Written By the Black Knight of Destruction
그러면 UTF-8과 UTF-16간에 변환을 따로 해 주어야 하나요?
그러면 UTF-8과 UTF-16간에 변환을 따로 해 주어야 하나요?
한다면 어떤 방식으로 해야 하나요?
그러면 프로그램 덩치가 너무 커지지 않을까 약간 우려되기도 합니다만..
---
"The truth will make you free."(John 8:32)
"I am the way, and the truth, and the life: no one comes to the Father but through Me."(John 14:6)
---
“내게 능력주시는 자 안에서 내가 모든 것을 할 수 있느니라.”(빌립보서 4:13)
http://www.kristalinfo.com/K-
http://www.kristalinfo.com/K-Lab/unicode/Unicode_intro-kr.html
위 페이지에서 UTF-8, UTF-16 인코딩에 대해 잘 설명되어 있습니다.
변환은 간단하게 됩니다. 완성형 분석할때처럼 복잡한 코드테이블 같은건 필요없습니다.
Written By the Black Knight of Destruction
Written By the Black Knight of Destruction
잘
잘 되는데요..
출력
틀렸습니다.
윗분처럼 깨져 나와야 정상입니다. 재현방법에 문제가 있습니다.
Hello World.
뭐가 틀렸고
뭐가 틀렸고 재현방법에 문제는 무엇인가요?
일단.
sparc 서버에 하셨나요? 빅인디언이네요. 설마 PowerPC는 아니시겠죠. ^^;
암튼.
> echo "갉" > test
> od -x test && hexdump test
0000000 b0ea 0a89
0000004
> cat test
갉
결국 UTF-8 포맷인 문자 '갉'을 저장한거지 UTF-8파일로 저장한건 아닙니다.
Hello World.
BOM입니다.
파일을 읽어서 3바이트만 hex 로 찍어보세요.
URL : http://en.wikipedia.org/wiki/Byte_Order_Mark
Hello World.
x86입니다. -_-;; 원래
x86입니다. -_-;; 원래 애당초 UTF-8에서는 엔디안에 따른 차이가 없습니다.
od -x 하면 2바이트씩 묶는데 엔디안에 따라서 출력이 다르게 되는것 뿐입니다.
제가 한것처럼 od -t x1으로 해보시면 똑같이 나올겁니다.
그리고 BOM 얘기하시는데 유닉스 계열에서는 UTF-8에서 BOM을 잘 안씁니다.
왜 안쓰는지는 위키피디아 찾아보면 나옵니다.
그리고 파일 앞에 BOM을 넣고도 똑같이 돌려봤는데 출력은 다음과 같습니다.
UTF-8의 BOM인 EF BB BF 가 결국 U+FEFF를 UTF-8로 변환한 것이므로 당연한 결과라고 보여지네요.
전혀 이상한 결과가 나온다면 fwscanf()의 리턴값을 체크해 봐야 되거 같네요.
에서 성공했으면 n이 1이 되고 에러면 0이나 -1이 나올겁니다.
제가 테스트한 환경은 Ubuntu 7.10, gcc 4.1.2, 컴파일 명령은 "gcc -Wall -std=c99 -O0 -ggdb3 -o a a.c", 로켈은 ko_KR.UTF-8, en_US.UTF-8 두가지 다 해봤습니다.
잘 보니까 윈도에서만 이런 문제가 발생하는군요.
VirtualBox를 이용해 우분투 상에서 다시 컴파일해보니까 무리없이 잘 읽혔습니다.
이건 Windows의 문제일까요? 저는 Windows상에서 Code::Block + MinGW + gcc조합을 쓰고 있는지라.
---
"The truth will make you free."(John 8:32)
"I am the way, and the truth, and the life: no one comes to the Father but through Me."(John 14:6)
---
“내게 능력주시는 자 안에서 내가 모든 것을 할 수 있느니라.”(빌립보서 4:13)
음.. 대략 미스테리가
음.. 대략 미스테리가 풀린듯 하네요..
'갉'을 utf-8로 하면 EA B0 89 가 되고..
EA B0 가 cp949로 '媛'이 되네요..
MinGW 에서는 표준 C 함수를 윈도우에서 제공하는 라이브러리에 있는걸로 씁니다. (아마도 msvcrt.dll)
그런데 이 라이브러리가 좀 오래된거라서 표준을 제대로 지원하지 않습니다. 대표적인 문제로 printf에서 64비트 정수를 출력하기 위해서 %lld 대신에 %I64d 를 써야 되죠..
msdn가서 보니까 fopen함수에서 ccs는 visual c++ 2005, 2008에서만 지원하고 2003 이전은 지원 안하네요.
(http://msdn.microsoft.com/en-us/library/yeby3zcb.aspx)
따라서 윈도우에 기본적으로 들어가있는 라이브러리도 ccs를 지원 안할겁니다.
이런경우라면 윈도우는 이른바 ANSI 인코딩을 사용합니다.
이게 뭐냐면 제어판에 보면 유니코드를 지원하지 않는 응용프로그램을 위한 언어설정이 있는데
이걸 한국어로 하면 ANSI 인코딩은 codepage 949가 되고
이게 English(US)면 ANSI 인코딩은 codepage 437이 됩니다.
결론은 윈도우에서는 fopen에서 ccs=UTF-8을 무시하고 입력파일을 cp949로 간주해서 처리를 한것으로 보입니다.
확인해보려면 제어판에서 앞에서 말한 설정을 바꿔놓고 해보면 되겠죠. (재부팅 필요)
English(US)로 바꾸면 EA가 cp437로 해석되서 Ω(U+03A9)가 나올겁니다.
그러면 Windows에서 UTF-8을 온전히 다루려면 어떤 꼼수를 써야 하나요?
그러면 Windows에서 UTF-8을 온전히 다루려면 어떤 꼼수를 써야 하나요?
Notepad도 UTF-8을 지원하기 위해서 어떤 꼼수를 썼을지 모를 일입니다;
---
"The truth will make you free."(John 8:32)
"I am the way, and the truth, and the life: no one comes to the Father but through Me."(John 14:6)
---
“내게 능력주시는 자 안에서 내가 모든 것을 할 수 있느니라.”(빌립보서 4:13)
Windows API에서
Windows API에서 제공하는 MultiByteToWideChar 함수를 쓰면 utf-8에서 utf-16로 변환할수 있습니다.
역으로는 WideCharToMultiByte 를 사용하면 됩니다.
아니면 iconv같은 라이브러리 사용해도 되고 직접 변환하는 코드를 짜도 되겠죠..
댓글 달기