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.