C ++ 문자열 (또는 char *)을 wstring (또는 wchar_t *)으로 변환


171
string s = "おはよう";
wstring ws = FUNCTION(s, ws);

s의 내용을 ws에 어떻게 할당합니까?

Google을 검색하고 일부 기술을 사용했지만 정확한 콘텐츠를 할당 할 수 없습니다. 내용이 왜곡되었습니다.


7
strings8 비트 이상의 문자를 허용 하지 않는다고 생각 합니다. 이미 UTF-8로 인코딩되어 있습니까?
— kennytm

3
"おはよう"시스템 인코딩 문자열을 만드는 시스템 인코딩은 무엇입니까 ?
— sbi

나는 MSVC가 그것을 받아 들여서 UTF-8과 같은 멀티 바이트 인코딩으로 만들 것이라고 믿는다.
— Potatoswatter

1
@ Potatoswatter : MSVC는 기본적으로 UTF-8을 사용하지 않습니다. 해당 문자를 입력하면 파일을 변환 할 인코딩을 요청하고 기본적으로 코드 페이지 1252로 설정됩니다.
— Mooing Duck

2
@ Samir : 더 중요한 것은 파일 의 인코딩이 무엇 입니까? 해당 문자열을 파일의 시작 부분으로 이동하고 해당 부분의 16 진 덤프를 표시 할 수 있습니까? 우리는 아마 그것으로부터 그것을 식별 할 수 있습니다.
— Mooing Duck

답변:


239

예제의 입력 문자열 (お は よ う)이 UTF-8로 인코딩되어 있다고 가정하면 (유형에 따라 다르지 않지만이 설명을 위해 있다고 가정합시다 :-)) 유니 코드 문자열 표준 라이브러리 (C ++ 11 이상)만으로도 문제를 완전히 해결할 수 있습니다.

TL; DR 버전 :

#include <locale>
#include <codecvt>
#include <string>

std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string narrow = converter.to_bytes(wide_utf16_source_string);
std::wstring wide = converter.from_bytes(narrow_utf8_source_string);

더 긴 온라인 컴파일 및 실행 가능 예제 :

(모두 동일한 예를 보여줍니다. 중복을위한 많은 것들이 있습니다 ...)

참고 (이전) :

주석에서 지적하고 https://stackoverflow.com/a/17106065/6345 에서 설명했듯이 표준 라이브러리를 사용하여 UTF-8과 UTF-16 사이를 변환하면 다른 플랫폼에서 결과에 예기치 않은 차이가 발생할 수 있습니다 . 더 나은 변환을 위해서는 http://en.cppreference.com/w/cpp/locale/codecvt_utf8에std::codecvt_utf8 설명 된대로 고려 하십시오

참고 (신규) :

codecvtC ++ 17 에서는 헤더가 더 이상 사용되지 않으므로이 답변에 제시된 솔루션에 대한 우려가 제기되었습니다. 그러나, C ++ 표준위원회에서 중요한 문 추가 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0.html 말을

이 라이브러리 구성 요소는 적절한 교체가 표준화 될 때까지 옆으로 Annex D로 폐기해야합니다.

따라서 가까운 미래 codecvt에이 답변 의 솔루션은 안전하고 휴대 가능합니다.


2
VS 파일을 어떤 인코딩으로 저장하는지 확인
— Johann Gerell

9
이것은 C ++ 11 전용입니다.
— bk138

1
minGW (gcc / g ++ 4.8.1 및 -std = c ++ 11)에는 codecvt 헤더가 없습니다. 대안이 있습니까?
— 브라이언 잭

1
std::codecvt_utf8초보자를위한 예를 들어 주시기 바랍니다
— Noitidart

14
참고 <codecvt>C ++ 17부터 사용되지 않습니다됩니다.
— tambre

47
int StringToWString(std::wstring &ws, const std::string &s)
{
    std::wstring wsTmp(s.begin(), s.end());

    ws = wsTmp;

    return 0;
}

93
모든 문자가 단일 바이트 인 경우에만 작동합니다 (예 : ASCII 또는 ISO-8859-1) . UTF-8을 포함하여 멀티 바이트는 비참하게 실패합니다. 질문에는 분명히 멀티 바이트 문자가 포함됩니다.
— Mark Ransom

28
이 대답은 분명히 불충분하며 넓은 문자로 좁은 문자를 복사하는 것 외에는 아무것도하지 않습니다. 멀티 바이트 또는 utf8 인코딩 문자열에서 utf16 wstring으로 올바르게 이동하는 방법은 다른 답변, 특히 Johann Gerell의 답변을 참조하십시오.
— DLRdave

10
이 답변은 위험하며 아마도 ASCII가 아닌 시스템에서 중단 될 수 있습니다. 즉, 아랍어 파일 이름은이 핵에 의해 엉망이됩니다.
— Stephen

9
이 답변은 질문 본문의 뉘앙스를 무시하고 질문 제목에 중점을두면 유용합니다. 있는 그대로, 질문의 제목은 매우 오해의 소지가 있으며 실제 질문을 반영하도록 변경되어야합니다.
— Anne Quinn

3
이것은 7 비트 ASCII 문자에서만 작동합니다. latin1의 경우 char이 부호없는 것으로 구성된 경우에만 작동합니다. char 유형이 서명 된 경우 (대부분의 경우) 문자> 127은 잘못된 결과를 제공합니다.
— huyc

32

귀하의 질문이 잘못 지정되었습니다. 엄밀히 말해 그 예는 구문 오류입니다. 하나,std::mbstowcs 아마도 당신이 찾고있는 것입니다.

C 라이브러리 기능이며 버퍼에서 작동하지만 TBohne (이전 Mooing Duck)이 제공하는 사용하기 쉬운 관용구입니다.

std::wstring ws(s.size(), L' '); // Overestimate number of code points.
ws.resize(std::mbstowcs(&ws[0], s.c_str(), s.size())); // Shrink to fit.

1
문자열 s = "お は よ う"; wchar_t * buf = 새로운 wchar_t [s.size ()]; size_t num_chars = mbstowcs (buf, s.c_str (), s.size ()); wstring ws (buf, num_chars); // ws = 왜곡됨
— Samir

1
@Samir : 런타임 인코딩이 컴파일 타임 인코딩과 동일한 지 확인해야합니다. setlocale컴파일러 플래그를 조정하거나 조정 해야 할 수도 있습니다 . Windows를 사용하지 않기 때문에 잘 모르겠지만 이것이 일반적인 기능이 아닌 이유입니다. 가능하면 다른 답변을 고려하십시오.
— Potatoswatter

1
std::string ws(s.size()); ws.resize(mbstowcs(&ws[0], s.c_str(), s.size());RAII FTW
— Mooing Duck

2
@WaffleSouffle 날짜가 지났습니다. 2011 년 이후로 연속적인 구현이 필요했으며 그 구현은 그보다 오래 전에 그러한 트릭을 종료했습니다.
— Potatoswatter

1
mingw와 같은 일부 환경에는 여전히 codecvt 헤더가 없으므로 이전의 '더 나은'솔루션 중 일부는 작동하지 않습니다.이 문제는 여전히 2014 년 12 월 현재 mingw에서 좋은 해결책이 없습니다.
— Brian Jack

18

누군가가 필요로하는 경우를 대비하여 C ++ 11 이전의 Windows API 전용 :

#include <stdexcept>
#include <vector>
#include <windows.h>

using std::runtime_error;
using std::string;
using std::vector;
using std::wstring;

wstring utf8toUtf16(const string & str)
{
   if (str.empty())
      return wstring();

   size_t charsNeeded = ::MultiByteToWideChar(CP_UTF8, 0, 
      str.data(), (int)str.size(), NULL, 0);
   if (charsNeeded == 0)
      throw runtime_error("Failed converting UTF-8 string to UTF-16");

   vector<wchar_t> buffer(charsNeeded);
   int charsConverted = ::MultiByteToWideChar(CP_UTF8, 0, 
      str.data(), (int)str.size(), &buffer[0], buffer.size());
   if (charsConverted == 0)
      throw runtime_error("Failed converting UTF-8 string to UTF-16");

   return wstring(&buffer[0], charsConverted);
}

최적화 할 수 있습니다. 를 사용하여 문자열을 이중으로 복사 할 필요가 없습니다 vector. 간단히 문자열의 문자를 예약 한 wstring strW(charsNeeded + 1);다음 변환을위한 버퍼로 사용하십시오 &strW[0]. 마지막으로 변환 후 마지막 널이 있는지 확인하십시오strW[charsNeeded] = 0;
— c00000fd

1
@ c00000fd, 내가 아는 한 std :: basic_string 내부 버퍼는 C ++ 11 표준 이후에만 연속적이어야합니다. 내 코드는 게시물 맨 위에 언급 된 것처럼 C ++ 11 이전입니다. 따라서 & strW [0] 코드는 표준을 준수하지 않으며 런타임시 합법적으로 충돌 할 수 있습니다.
— Alex Che

13

Windows / Visual Studio를 사용 하고 문자열을 wstring으로 변환 해야하는 경우 다음을 사용할 수 있습니다.

#include <AtlBase.h>
#include <atlconv.h>
...
string s = "some string";
CA2W ca2w(s.c_str());
wstring w = ca2w;
printf("%s = %ls", s.c_str(), w.c_str());

wstring을 문자열로 변환하는 동일한 절차 (때로는 codepage 를 지정해야 함 ) :

#include <AtlBase.h>
#include <atlconv.h>
...
wstring w = L"some wstring";
CW2A cw2a(w.c_str());
string s = cw2a;
printf("%s = %ls", s.c_str(), w.c_str());

코드 페이지 와 UTF8을 지정할 수 있습니다 (작업 할 때 매우 좋습니다) JNI / Java ). 표준 의 방법 UTF8에 표준 : : wstring의 변환은 표준 : : 문자열이 대답했다한다 .

// 
// using ATL
CA2W ca2w(str, CP_UTF8);

// 
// or the standard way taken from the answer above
#include <codecvt>
#include <string>

// convert UTF-8 string to wstring
std::wstring utf8_to_wstring (const std::string& str) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
    return myconv.from_bytes(str);
}

// convert wstring to UTF-8 string
std::string wstring_to_utf8 (const std::wstring& str) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
    return myconv.to_bytes(str);
}

코드 페이지 에 대해 더 알고 싶다면 소프트웨어에 관한 Joel의 흥미로운 기사가 ​​있습니다 : 절대적으로 모든 소프트웨어 개발자는 절대적으로 유니 코드와 문자 세트에 대해 반드시 알아야 합니다

이 CA2W (Ansi에서 Wide = unicode로 변환) 매크로는 ATL 및 MFC 문자열 변환 매크로의 일부입니다. 샘플이 포함 된 .

때로는 보안 경고 # 4995를 비활성화해야합니다. 다른 해결 방법을 모르겠습니다 (VS2012에서 WindowsXp 용으로 컴파일 할 때 발생합니다).

#pragma warning(push)
#pragma warning(disable: 4995)
#include <AtlBase.h>
#include <atlconv.h>
#pragma warning(pop)

편집 : 글쎄요, 이 기사 에 따르면 Joel의 기사는 다음과 같이 나타납니다. 기사 : 모든 프로그래머가 텍스트로 작업하기 위해 인코딩 및 문자 집합에 대해 반드시 알아야 할 사항 .


영어를 모국어로 사용하는 사람이 아닙니다. 적합하다고 생각되면 수정하십시오.
— lmiguelmh 2014

downvoter는 무엇입니까? 대답에 어떤 문제가 있습니까?
— lmiguelmh 2016 년

아마도 이식 불가능한 코드를 홍보한다는 사실입니다.
— Pavel Minaev

그렇기 때문에 이것이 Windows / Visual Studio에서만 작동한다고 말한 것입니다. 그러나 적어도이 해결책은 맞지만 이것이 아닙니다 :char* str = "hello worlddd"; wstring wstr (str, str+strlen(str));
— lmiguelmh

추가 사항 : CA2W는 ATL의 네임 스페이스에 있습니다. (ATL :: CA2W)
— Val

12

여기에 결합하는 방법 string, wstring그리고에 혼합 문자열 상수 wstring. 사용wstringstream수업을 .

멀티 바이트 문자 인코딩에는 작동하지 않습니다. 이것은 유형 안전을 버리고 std :: string에서 7 비트 문자를 std : wstring의 각 문자의 하위 7 비트로 확장하는 바보 같은 방법입니다. 이것은 7 비트 ASCII 문자열이 있고 넓은 문자열이 필요한 API를 호출해야하는 경우에만 유용합니다.

#include <sstream>

std::string narrow = "narrow";
std::wstring wide = L"wide";

std::wstringstream cls;
cls << " abc " << narrow.c_str() << L" def " << wide.c_str();
std::wstring total= cls.str();

답은 흥미로워 보인다. 조금 설명해 주시겠습니까? 멀티 바이트 인코딩에 왜 효과가 있습니까?
— wh1t3cat1k

인코딩 체계는 스토리지 클래스와 직교합니다. string1 바이트 문자를 wstring저장하고 2 바이트 문자를 저장합니다. utf8과 같은 것은 멀티 바이트 문자를 일련의 1 바이트 값으로 저장합니다 string. 문자열 클래스는 인코딩에 도움이되지 않습니다. C ++로 클래스를 인코딩하는 전문가는 아닙니다.
— Mark Lakata

2
얼마나 짧고 간단한 지, 왜 이것이 최선의 대답이 아닌가? 해당되지 않는 경우는?
— Ryuu

@ MarkLakata, 첫 번째 의견에 대한 귀하의 답변을 읽었지만 여전히 확실하지 않습니다. 멀티 바이트 문자에서도 작동합니까? 즉, 이 답변 과 같은 함정 이 발생하기 쉽지 않습니까?
— Marc.2377

@ Marc.2377 멀티 바이트 문자 인코딩에는 작동하지 않습니다. 이것은 타입 안전을 버리고 7 비트 문자를에서 std::string각 문자의 하위 7 비트로 확장하는 바보 같은 방법 입니다 std:wstring. 이것은 7 비트 ASCII 문자열이 있고 넓은 문자열이 필요한 API를 호출해야하는 경우에만 유용합니다. 좀 더 정교한 것이 필요하면 stackoverflow.com/a/8969776/3258851을 참조하십시오.
— Mark Lakata

11

~ char*까지 wstring:

char* str = "hello worlddd";
wstring wstr (str, str+strlen(str));

~ string까지 wstring:

string str = "hello worlddd";
wstring wstr (str.begin(), str.end());

이것은 변환되는 문자열에 ASCII 문자 만 포함 된 경우에만 잘 작동합니다.


7
인코딩이 Windows-1252 인 경우에만 작동하기 때문에 문제의 문자를 포함 할 수 없습니다.
— Mooing Duck

3
ASCII를 다룰 때 오류가 발생하기 쉬운 방법입니다. 앱을 최신 API로 이식 할 때 눈에 띄는 유스 케이스입니다.
— Sid Sarasvati

이것은 방법 이 아닙니다 . Visual Studio를 사용하는 경우을 사용해야합니다 atlconv.h. 다른 답변을 확인하십시오.
— lmiguelmh

7

Boost.Locale 사용하기 :

ws = boost::locale::conv::utf_to_utf<wchar_t>(s);

5

이 변형은 실제 생활에서 내가 가장 좋아하는 것입니다. 유효한 UTF-8 인 경우 입력을 각각로 변환합니다 wstring. 입력이 손상된 경우 wstring단일 바이트로 구성됩니다. 입력 데이터의 품질을 실제로 확신 할 수없는 경우 매우 유용합니다.

std::wstring convert(const std::string& input)
{
    try
    {
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        return converter.from_bytes(input);
    }
    catch(std::range_error& e)
    {
        size_t length = input.length();
        std::wstring result;
        result.reserve(length);
        for(size_t i = 0; i < length; i++)
        {
            result.push_back(input[i] & 0xFF);
        }
        return result;
    }
}

1
방금 답변에
— 따라이

2

QT가 있고 기능과 물건을 구현하기가 게으른 경우 사용할 수 있습니다

std :: string str; QString (str) .toStdWString ()


거의, 그러나 생성자는 어떤 이유로 문자열을 받아 들일 수 QString없기 때문에로 시작해야합니다 QString.
— bobsbeenjamin


이거 좋은데. 또한 .c_str () 을 사용하여 QString이 생성자에서 문자열을 허용하도록 할 수 있습니다 .
— miep

1

방법 s2ws가 잘 작동합니다. 희망이 도움이됩니다.

std::wstring s2ws(const std::string& s) {
    std::string curLocale = setlocale(LC_ALL, ""); 
    const char* _Source = s.c_str();
    size_t _Dsize = mbstowcs(NULL, _Source, 0) + 1;
    wchar_t *_Dest = new wchar_t[_Dsize];
    wmemset(_Dest, 0, _Dsize);
    mbstowcs(_Dest,_Source,_Dsize);
    std::wstring result = _Dest;
    delete []_Dest;
    setlocale(LC_ALL, curLocale.c_str());
    return result;
}

6
안전하지 않은 방식으로 동적 메모리를 할당 한 다음 버퍼에서 문자열로 데이터를 복사하는 이러한 답변에는 무엇이 있습니까? 왜 안전하지 않은 중개인을 제거하지 않습니까?
— Mooing Duck

hahakubile, ws2s와 비슷한 것을 기쁘게 해 줄 수 있습니까?
— 크리스티안

1

내 자신의 테스트 (Windows 8, 2010)에서 mbstowcs는 실제로 원래 문자열을 손상시킬 수 있으며 ANSI 코드 페이지에서만 작동합니다. MultiByteToWideChar / WideCharToMultiByte도 문자열 손상을 일으킬 수 있지만 모르는 문자를 '?'로 바꾸는 경향이 있습니다. 물음표이지만 mbstowcs는 알 수없는 문자가 발생하고 바로 그 시점에서 문자열을자를 때 멈추는 경향이 있습니다. (핀란드어 창에서 베트남어 문자를 테스트했습니다).

따라서 아날로그 ansi C 함수보다 Multi * -windows api 함수를 선호하십시오.

또한 한 코드 페이지에서 다른 코드 페이지로 문자열을 인코딩하는 가장 짧은 방법은 MultiByteToWideChar / WideCharToMultiByte API 함수 호출을 사용하지 않고 아날로그 ATL 매크로 인 W2A / A2W를 사용하는 것입니다.

따라서 위에서 언급 한 아날로그 기능은 다음과 같습니다.

wstring utf8toUtf16(const string & str)
{
   USES_CONVERSION;
   _acp = CP_UTF8;
   return A2W( str.c_str() );
}

_acp는 USES_CONVERSION 매크로에서 선언됩니다.

또는 오래된 데이터를 새로운 데이터로 변환 할 때 종종 놓치는 기능 :

string ansi2utf8( const string& s )
{
   USES_CONVERSION;
   _acp = CP_ACP;
   wchar_t* pw = A2W( s.c_str() );

   _acp = CP_UTF8;
   return W2A( pw );
}

그러나 해당 매크로의 스택은 W2A 또는 A2W 매크로를 사용한 후 동일한 함수에 대해 루프 또는 재귀 루프에 사용하지 마십시오. ASAP를 반환하는 것이 좋습니다. 스택은 일시적인 변환에서 벗어날 수 있습니다.


1

문자열을 wstring으로

std::wstring Str2Wstr(const std::string& str)
{
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo(size_needed, 0);
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

wstring을 문자열로

std::string Wstr2Str(const std::wstring& wstr)
{
    typedef std::codecvt_utf8<wchar_t> convert_typeX;
    std::wstring_convert<convert_typeX, wchar_t> converterX;
    return converterX.to_bytes(wstr);
}

1
이 Str2Wstr에는 0 종료에 문제가 있습니다. "+"를 통해 더 이상 생성 된 wstring을 연결할 수 없습니다 (wstring s3 = s1 + s2에서와 같이). 곧이 문제를 해결하는 답변을 게시 할 것입니다. 먼저 메모리 누수를 테스트해야합니다.
— thewhiteambit

-2

string s = "おはよう"; 오류입니다.

wstring을 직접 사용해야합니다.

wstring ws = L"おはよう";

1
그것은 작동하지 않을 것입니다. BMP 이외의 문자를 C 이스케이프 시퀀스로 변환해야합니다.
— Dave Van den Eynde

3
@Dave : 컴파일러가 소스 파일에서 유니 코드를 지원하고 지난 10 년간의 모든 것 (visual studio, gcc, ...)을 지원하는 경우 작동합니다.
— Thomas Bonini

안녕하세요. 기본 시스템 인코딩에 관계없이 (예 : 기본 시스템 인코딩으로 아랍어를 사용할 수 있음) L "お は よ う"의 소스 코드 파일 인코딩이 작동하려면 어떻게해야합니까? UTF-16이어야합니까, 아니면 .cpp 파일 인코딩을 위해 BOM없이 UTF-8을 가질 수 있습니까?
— Afriza N. Arief

2
@afriza : 그것은 당신의 컴파일 지원으로별로 중요 한하지 않습니다는
— 토마스 Bonini

2
오류가 아닙니다. "좁은"문자열의 확장 문자는 멀티 바이트 시퀀스에 매핑되도록 정의됩니다. 컴파일러는 OS가 지원하는 한 최소한의 지원만으로이를 지원해야합니다.
— Potatoswatter

-2

이 코드를 사용하여 문자열을 wstring으로 변환하십시오.

std::wstring string2wString(const std::string& s){
    int len;
    int slength = (int)s.length() + 1;
    len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); 
    wchar_t* buf = new wchar_t[len];
    MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
    std::wstring r(buf);
    delete[] buf;
    return r;
}

int main(){
    std::wstring str="your string";
    std::wstring wStr=string2wString(str);
    return 0;
}

3
이 질문에는 Windows에 대한 언급이 없으며이 답변은 Windows 전용입니다.
— Johann Gerell

CP_ACP틀림없이 잘못된 주장입니다. 갑자기 실행중인 스레드의 환경 상태는 코드의 동작에 영향을 미칩니다. 바람직하지 않습니다. 변환시 고정 문자 인코딩을 지정하십시오. (그리고 오류 처리를 고려하십시오.)
— IInspectable
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.