[MFC] 유니코드 멀티바이트 UTF-8 문자열 인코딩 변환 모음(퍼옴)

2015. 4. 23. 17:57IT-개발/winapi 및 MFC

반응형

제목에서 밝힌 바와 같이 내용이 넘 좋아서 퍼왔습니다~ ^^

(http://yeobi27.tistory.com/280)


유니코드 -> 멀티바이트

1
2
3
4
5
wchar_t strUnicode[256] = {0,};
char    strMultibyte[256] = {0,};
wcscpy_s(strUnicode,256,L"유니코드");
int len = WideCharToMultiByte( CP_ACP, 0, strUnicode, -1, NULL, 0, NULL, NULL );   
WideCharToMultiByte( CP_ACP, 0, strUnicode, -1, strMultibyte, len, NULL, NULL );

stl이용

1
2
3
4
wstring strUni = L"유니코드";
int len = WideCharToMultiByte( CP_ACP, 0, &strUni[0], -1, NULL, 0, NULL, NULL );
string strMulti(len,0);
WideCharToMultiByte( CP_ACP, 0,  &strUni[0], -1, &strMulti[0], len, NULL, NULL );


멀티바이트 -> 유니코드

1
2
3
4
5
wchar_t strUnicode[256] = {0,};
char    strMultibyte[256] = {0,};
strcpy_s(strMultibyte,256,"멀티바이트");
int nLen = MultiByteToWideChar(CP_ACP, 0, strMultibyte, strlen(strMultibyte), NULL, NULL);
MultiByteToWideChar(CP_ACP, 0, strMultibyte, strlen(strMultibyte), strUnicode, nLen);

stl이용

1
2
3
4
string strMulti = "멀티바이트"
int nLen = MultiByteToWideChar(CP_ACP, 0, &strMulti[0], strMulti.size(), NULL, NULL);
wstring strUni(nLen,0);
MultiByteToWideChar(CP_ACP, 0, &strMulti[0], strMulti.size(), &strUni[0], nLen);


유니코드 -> UTF-8

1
2
3
4
wchar_t strUni[256] =L"유니코드";
char strUtf8[256] ={0,};
int nLen = WideCharToMultiByte(CP_UTF8, 0, strUni, lstrlenW(strUni), NULL, 0, NULL, NULL);
WideCharToMultiByte (CP_UTF8, 0, strUni, lstrlenW(strUni), strUtf8, nLen, NULL, NULL);


UTF-8 -> 유니코드로 변환

1
2
3
4
5
wchar_t strUnicode[256] = {0,};
char    strUTF8[256] = {0,};
strcpy_s(strUTF8,256,"utf-8글자..");// 이건 사실 멀티바이트지만 UTF8이라고 생각해주세요 -_-;;
int nLen = MultiByteToWideChar(CP_UTF8, 0, strUTF8, strlen(strUTF8), NULL, NULL);
MultiByteToWideChar(CP_UTF8, 0, strUTF8, strlen(strUTF8), strUnicode, nLen);


기본적으로 UTF-8로 변형할땐 유니코드 상태에서만 변형을 시켜야 된다!.

 만약 멀티 바이트를 UTF-8로 변형하고 싶을때에는
   멀티바이트 -> 유니코드(UTF-16) -> UTF-8 
UTF-8을 멀티바이트로 변형할때에는
   UTF-8 -> 유니코드(UTF-16) -> 멀티바이트..
 


그런데 위와 같은 방식은.. 윈도우 환경에서만 사용한다면 너무 복잡하다...

우리 위대하신 MS에서 만들어주신게 있는데..

1
2
3
4
5
6
7
8
9
10
11
12
#include <atlstr.h> // 요기에 정의..  이거하면 MFC사용안하고도 CString를 사용할수 있다
void main()
{
  wstring strUni = CA2W("멀티바이트를 유니코드로 변환");
  string strMulti = CW2A(L"유니코드를 멀티바이트로 변환");
  string strUTF8 = CW2A(L"유니코드를 UTF8로변환",CP_UTF8);
  //string에서 포인터 얻어오는게 c_str()이듯.
  //CA2W나 CW2A에서 포인터 얻어오는건 m_psz 이다..
  //그리고 CA2W CW2A는 기본적으로 CString 즉 (CAtlString)에 기반을 두고 고 있기때문에.
  //CString를 사용할때 가장 빠른다!!.
  // 만약 멀티 플레폼을 기준으로 한다면 CA2W는 사용 못함!
}


사용하기도 쉽고 속도면에서 MultiByteToWideChar,WideCharToMultiByte 보다 빠르다...


참고로 W는 wide , A는 ansi ,T는 TCHAR 이다.


펌 : http://icartsh.tistory.com/13


===================================================================================================================================================


Unicode 상에서 CString을 std:string을 바꾸기


std::string strMain( CW2A( cstrMain.GetString() ) );


or


CString a = "ASDF";
std::string filename;
filename = CW2A(a);



펌 : http://chodalho.wordpress.com/2010/07/09/unicode-%EC%83%81%EC%97%90%EC%84%9C-cstring%EC%9D%84-stdstring%EC%9D%84-%EB%B0%94%EA%BE%B8%EA%B8%B0/


=====================================================================================================================================================


MultiByteToWideChar를 이용한 변환

MultiByteToWideChar()함수와 WideCharToMuliByte()함수를 사용해서 인코딩을 변환해 주는 것도 가능합니다. 이 두함수는 윈도우에서만 지원합니다. 따라서 OS 디펜던시가 없는 라이브러라 같은 것을 개발하신다면 이 두함수는 사용하실 수 없긴 하지만 많은 윈도우 개발자들이 사랑하는 함수죠. 

먼저 MBCS를 UTF-16으로 바꾸는 함수입니다.

int MultiByteToWideChar(
UINT CodePage, // 원본 스트링의 현재 인코딩 상태
DWORD dwFlags, // 0을 쓰면 된다.
LPCSTR lpMultiByteStr, // 변환하려는 문자열
int cbMultiByte, // -1을 넣으면 lpMultiByteStr의 길이를 알아서 계산
LPWSTR lpWideCharStr, // 변환된 유니코드를 저장할 공간
int cchWideChar // 유니코드를 저장할 공간의 사이즈
);

첫번째 인자에는 CP_ACP나 UTF-8둘중 하나를 넣으시면 됩니다. 
이함수는 특이한 기능이 있는데 맨마지막 인자에 0을 넣으면 필요한 wchar_t의 공간을 리턴합니다. 이를 이용해서 변환된 문자열에 딱맞는 공간을 할당 하실 수 있습니다. 다음은 반대로 UTF-16을 MBCS로 바꾸는 함수입니다.

int WideCharToMultiByte(
UINT CodePage, // 변환 타겟 인코딩
DWORD dwFlags, // 0
LPCWSTR lpWideCharStr, // 원본 스트링
int cchWideChar, // -1을 넣으면 원본 스트링 길이가 자동할당
LPSTR lpMultiByteStr, // 목적지
int cbMultiByte, // 목적지 사이즈
LPCSTR lpDefaultChar, // 실패시 사용
LPBOOL lpUsedDefaultChar // 실패 여부 판단
);

MultiByteToWideChar()함수와 거의 같은데 인자가 두개더 있습니다. lpDefaultChar인자는 인코딩이 실패했을 때 실패한 문자열 대신 사용될 문자열입니다. 보통 NULL로 지정하시면 됩니다. 마지막 인자 lpUsedDefaultChar는 변환에 실패한 문자가 하나라도 있을 때 TRUE를 리턴합니다. 유니코드는 MBCS보다 사이즈가 큰 집합이기 떄문에 MBCS에서 유니코드로의 변환은 실패할 일이 없지만 반대는 실패할 수도 있음을 기억하셔야 합니다.


USE_CONVERSION 를 이용해 변환

이 매크로를 이용하면 아주 쉽게 문자열을 변환할 수 있습니다. 사용법은 아래와 같습니다.

#include <atlconv.h> // 필요 include
#pragma comment(lib, "atls.lib") // 필요 lib
void SomeFunction()
{
USES_CONVERSION; // 먼저 적으셔야 합니다.
CAtlStringW wideStr[]=L"abc가나다";
CAtlStringA ansiStr;
ansiStr = W2A(widechar); // UTF-16을 MBCS로 바꿉니다.
}

W2A말고도 여러 매크로를 제공하는데요. 아래와 같습니다. (const 변환용 매크로 제외)
매크로설명
A2WLPCSTR -> LPWSTR
W2ALPCWSTR -> LPSTR
A2TLPCSTR -> LPTSTR
T2ALPCTSTR -> LPSTR
T2OLELPCTSTR -> LPOLESTR
OLE2TLPCOLESTR -> LPCSTR

이 매크로는 사용하기엔 편하지만 UTF8을 UTF-16 으로 변환하는데 쓰실 수 없습니다. 또 주의 해야 할 것이 있는데요. 각 매크로를 사용할 떄 변환에 필요한 공간이 스택에 할당된다는 점입니다. 따라서 실제적으로 아래를 주의 하셔야 합니다.
  • 너무 큰 스트링을 변환하고 시도하면 스택 오버 플로가 날 수 있습니다.
  • 루프 안에서 과도한 변환을 시도하면 스택 오버 플로가 날 수 있습니다.
  • 스택에서 잡힌 공간이기 때문에 매크로의 결과를 리턴시키면 안됩니다.

CA2W계열의 클래스를 이용한 변환

USE_CONVERSION 를 이용한 변환이 편하긴 한데 위에서 말한대로 문제가 좀 있기 때문에 ATL 7.0이후 CATW계열의 클래스들이 새로 등장했습니다. 이 아이는 클래스인데다가 기본적으로 128바이트의 내부 버퍼를 가지고 있고(변경 가능 합니다만..), 이보다 크면 알아서 힙에 동적할당을 해주는 똑똑한 놈입니다.

#include <atlconv.h> // 필요 include
#pragma comment(lib, "atls.lib") // 필요 lib
void SomeFunction()
{
CA2W p ("123가나다"); // 클래스 선언
CA2WEX<256> p2 ("123마바사"); // EX를 붙이면 내부 버퍼 사이즈를
// 변경시킬 수 있습니다만 새로운
// 사이즈별로 코드가 새로 생깁니다.
CAtlStringW str(p); // p가 LPWSTR을 리턴합니다.
CAtlStringW str2 = p2; // p2가 LPWSTR을 리턴합니다.
}

이런식으로 사용합니다. 주의할 점은 역시 위 코드에서 보이는 p를 리턴 시키면 안됩니다.(당연한 이야기지만) CA2W외 그밖의 클래스 들은 아래와 같습니다. (아래 목록은 cosnt와 버퍼 사이즈를 변경할 수 있는 EX가 붙어 있는 것들이 제외 되었습니다.)
클래스설명
CA2WLPCSTR -> LPWSTR
CW2ALPCWSTR -> LPSTR
CA2TLPCSTR -> LPTSTR
CT2ALPCTSTR -> LPSTR
CT2OLELPCTSTR -> LPOLESTR
COLE2TLPCOLESTR -> LPCSTR
아쉬운 것이 있다면 UTF-8로의 변환을 지원하는 클래스가 있었다면 좀더 좋았을 텐데 이점이 조금 아쉽습니다.

참조 : http://cafe.naver.com/newchany.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=625

Tip : atlconv.h 를 인클루드 했는데도 CA2W 클래스를 찾을 수 없다는 컴파일 오류가 나온다면 atlconv.h 대신 atlbase.h 를 인클루드 하면 컴파일 오류를 해결할 수 있다.

추천 사용 방법
#include <atlbase.h>
#include <string>
inline std::wstring _A2U( IN CONST CHAR *str ) { ATL::CA2W ca2w( str ); return std::wstring( ca2w ); }
inline std::string _U2A( IN CONST WCHAR *str ) { ATL::CW2A cw2a( str ); return std::string( cw2a ); }
#define A2U( str ) (WCHAR *)_A2U( str ).c_str()
#define U2A( str ) (CHAR *)_U2A( str ).c_str()



< 사용후기 >

 - 아래 함수 이거 너무 편해서 좋은데, 웬만한 Loop 돌면 심심하면 STack OverFlow 발생하네요.

 - 나중에 PG이 왜 죽는지도 모르는... Data 양에 따라서 PG에 Bug / Error 가 발생하는 찾기 힘든 Bug를 양산할 수 있음돠~ ㅠㅠ


USES_CONVERSION;

W2A();

A2W();