วิธีการแปลง wstring เป็นสตริง?


204

คำถามคือวิธีการแปลง wstring เป็นสตริง?

ฉันมีตัวอย่างต่อไป:

#include <string>
#include <iostream>

int main()
{
    std::wstring ws = L"Hello";
    std::string s( ws.begin(), ws.end() );

  //std::cout <<"std::string =     "<<s<<std::endl;
    std::wcout<<"std::wstring =    "<<ws<<std::endl;
    std::cout <<"std::string =     "<<s<<std::endl;
}

เอาต์พุตที่มีบรรทัดที่ใส่ความคิดเห็นคือ:

std::string =     Hello
std::wstring =    Hello
std::string =     Hello

แต่ไม่มีเพียง:

std::wstring =    Hello

มีอะไรผิดปกติในตัวอย่างหรือไม่ ฉันสามารถทำการแปลงแบบด้านบนได้ไหม?

แก้ไข

ตัวอย่างใหม่ (คำนึงถึงคำตอบบางอย่าง) คือ

#include <string>
#include <iostream>
#include <sstream>
#include <locale>

int main()
{
    setlocale(LC_CTYPE, "");

    const std::wstring ws = L"Hello";
    const std::string s( ws.begin(), ws.end() );

    std::cout<<"std::string =     "<<s<<std::endl;
    std::wcout<<"std::wstring =    "<<ws<<std::endl;

    std::stringstream ss;
    ss << ws.c_str();
    std::cout<<"std::stringstream =     "<<ss.str()<<std::endl;
}

ผลลัพธ์คือ:

std::string =     Hello
std::wstring =    Hello
std::stringstream =     0x860283c

ดังนั้น stringstream ไม่สามารถใช้ในการแปลง wstring เป็นสตริง


4
คุณจะถามคำถามนี้โดยไม่ระบุการเข้ารหัสได้อย่างไร
David Heffernan

5
@tenfour: ทำไมต้องใช้std::wstringเลย? stackoverflow.com/questions/1049947/…
dalle

11
@ Dalle หากคุณมีข้อมูลที่เข้ารหัสด้วย UTF-16 แล้วไม่ว่า UTF-16 จะถือว่าเป็นอันตรายหรือไม่ และสำหรับสิ่งที่คุ้มค่าฉันไม่คิดว่ารูปแบบการเปลี่ยนแปลงใด ๆ จะเป็นอันตราย สิ่งที่เป็นอันตรายคือคนคิดว่าพวกเขาเข้าใจ Unicode เมื่อในความเป็นจริงพวกเขาไม่ได้
David Heffernan

2
มันจะต้องเป็นโซลูชั่นข้ามแพลตฟอร์ม?
ali_bahoo

2
@dalle มาตรฐาน c ++ ไม่ได้กล่าวถึง utf ในทางใดทางหนึ่ง (utf-8 หรือ utf-16) มีลิงค์ที่บอกว่าทำไม utf-16 ไม่สามารถเข้ารหัสด้วย wstring ได้หรือไม่
BЈовић

คำตอบ:


31

นี่คือวิธีแก้ปัญหาที่ใช้งานได้ตามคำแนะนำอื่น ๆ :

#include <string>
#include <iostream>
#include <clocale>
#include <locale>
#include <vector>

int main() {
  std::setlocale(LC_ALL, "");
  const std::wstring ws = L"ħëłlö";
  const std::locale locale("");
  typedef std::codecvt<wchar_t, char, std::mbstate_t> converter_type;
  const converter_type& converter = std::use_facet<converter_type>(locale);
  std::vector<char> to(ws.length() * converter.max_length());
  std::mbstate_t state;
  const wchar_t* from_next;
  char* to_next;
  const converter_type::result result = converter.out(state, ws.data(), ws.data() + ws.length(), from_next, &to[0], &to[0] + to.size(), to_next);
  if (result == converter_type::ok or result == converter_type::noconv) {
    const std::string s(&to[0], to_next);
    std::cout <<"std::string =     "<<s<<std::endl;
  }
}

โดยปกติจะใช้งานได้กับ Linux แต่จะสร้างปัญหาบน Windows


@Phillip: ส่วนใดของรหัสขึ้นอยู่กับ c-locale เป็นstd::setlocale(LC_ALL, "");ความจำเป็นจริงๆ?
smerlin

2
การใช้std::wcout.imbue(locale)ควรทำงานเช่นกันและมีประโยชน์ที่จะไม่เปลี่ยนสถานะทั่วโลก
smerlin

32
เสียงstd::wstring_convertจาก C ++ 11 ตัดเสียงรบกวนนี้ออกมามาก
Cubbi

7
@ ฟิลิปส์คุณหมายถึงอะไร "จะสร้างปัญหาให้กับ Windows" มีปัญหาอะไร
Gili

1
โค้ดด้านบนให้ (ดังที่คัดลอก) ให้ฉัน*** glibc detected *** test: malloc(): smallbin double linked list corrupted: 0x000000000180ea30 ***บน linux 64-bit (gcc 4.7.3) ใครบ้างที่ประสบปัญหานี้
hogliux

312

ในฐานะที่เป็น Cubbi ชี้ให้เห็นในหนึ่งในการแสดงความคิดเห็น, std::wstring_convert(C ++ 11) ให้เป็นโซลูชั่นที่เรียบง่ายเรียบร้อย (คุณต้อง#include <locale>และ<codecvt>):

std::wstring string_to_convert;

//setup converter
using convert_type = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_type, wchar_t> converter;

//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
std::string converted_str = converter.to_bytes( string_to_convert );

ฉันกำลังใช้การผสมผสานwcstombsและการจัดสรร / การจัดสรรคืนหน่วยความจำที่น่าเบื่อก่อนที่จะเจอสิ่งนี้

http://en.cppreference.com/w/cpp/locale/wstring_convert

ปรับปรุง (2013/11/28)

หนึ่งสมุทรสามารถระบุได้ดังนั้น (ขอบคุณ Guss สำหรับความคิดเห็นของคุณ):

std::wstring str = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes("some string");

ฟังก์ชั่น Wrapper สามารถระบุได้ดังนี้: (ขอบคุณ ArmanSchwarz สำหรับความคิดเห็นของคุณ)

std::wstring s2ws(const std::string& str)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.from_bytes(str);
}

std::string ws2s(const std::wstring& wstr)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.to_bytes(wstr);
}

หมายเหตุ: มีข้อโต้แย้งว่าstring/ wstringควรส่งผ่านไปยังฟังก์ชันเป็นการอ้างอิงหรือเป็นตัวอักษร (เนื่องจาก C ++ 11 และการอัปเดตคอมไพเลอร์) ฉันจะทิ้งการตัดสินใจไว้กับบุคคลที่นำไปใช้

หมายเหตุ: ฉันกำลังใช้std::codecvt_utf8รหัสด้านบน แต่หากคุณไม่ได้ใช้ UTF-8 คุณจะต้องเปลี่ยนเป็นการเข้ารหัสที่เหมาะสมที่คุณใช้:

http://en.cppreference.com/w/cpp/header/codecvt


25
โปรด +1 : นี่คือวิธีมาตรฐานอย่างเป็นทางการในการแปลงสตริง คุณยังสามารถใช้ from_bytes เพื่อแปลงวิธีอื่นได้ เพราะโดยส่วนตัวแล้วฉันชอบหนึ่ง liners นี่เป็นเวอร์ชั่นของฉัน:std::wstring str = std::wstring_convert<std::codecvt_utf<wchar_t>>().from_bytes("some string");
Guss

7
ดูเหมือนว่าen.cppreference.com/w/cpp/header/codecvtไม่มีให้บริการตั้งแต่ g ++ 4.8.2 ทั้งสองวิธี s2ws และ ws2s ไม่ทำงานภายใต้ลินุกซ์
Begui

5
ดูเหมือนว่าสิ่งนี้ถูกคัดค้าน ( stackoverflow.com/a/42946556/211176 ) คอมไพเลอร์ของฉันโยนข้อผิดพลาดเมื่อฉันพยายามเรียกใช้รหัสนี้
adam_0


5
สำหรับทุกคนที่กังวลเกี่ยวกับ C ++ 17 และความเข้ากันได้เพิ่มเติม (เนื่องจากการคัดค้าน) ดูได้ที่: stackoverflow.com/a/18597384/6205379
Timo

128

โซลูชันจาก: http://forums.devshed.com/c-programming-42/wstring-to-string-444006.html

std::wstring wide( L"Wide" ); 
std::string str( wide.begin(), wide.end() );

// Will print no problemo!
std::cout << str << std::endl;

ระวังว่าไม่มีการแปลงชุดตัวละครเกิดขึ้นที่นี่เลย สิ่งนี้ทำเพื่อกำหนดแต่ละการทำซ้ำwchar_tให้เป็นการcharแปลงที่ถูกตัดทอน มันใช้std :: string c'tor :

template< class InputIt >
basic_string( InputIt first, InputIt last,
              const Allocator& alloc = Allocator() );

ตามที่ระบุไว้ในความคิดเห็น:

ค่า 0-127 จะเหมือนกันในทุกการเข้ารหัสดังนั้นการตัดค่าที่น้อยกว่า 127 ผลลัพธ์ในข้อความเดียวกัน ใส่ตัวอักษรจีนแล้วคุณจะเห็นความล้มเหลว

-

ค่า 128-255 ของ windows codepage 1252 (ค่าเริ่มต้นเป็นภาษาอังกฤษของ Windows) และค่า 128-255 ของ unicode ส่วนใหญ่จะเหมือนกันดังนั้นถ้าเป็น codepage ที่คุณกำลังใช้อักขระส่วนใหญ่ควรถูกตัดให้เป็นค่าที่ถูกต้อง (ฉันคาดหวังทั้งหมดáและõในการทำงานฉันรู้ว่ารหัสของเราในที่ทำงานอาศัยสิ่งนี้สำหรับéซึ่งฉันจะแก้ไขในไม่ช้า)

และโปรดทราบว่ารหัสคะแนนในช่วง0x80 - 0x9FในWin1252จะไม่ทำงาน ซึ่งรวมถึง, œ, ž, Ÿ...


2
โดยปกติจะใช้กับ Visual Studio 10 เกิดอะไรขึ้น สิ่งนี้ควรทำให้เกิดการแยกที่ถูกตัดทอนจาก wchar_t เป็นถ่านสำหรับองค์ประกอบทั้งหมดของสตริงต้นฉบับ
Pedro Lamarão

6
... เมื่อไปถึงอักขระที่ไม่ใช่ละติน
JavaRunner

8
@ PedroLamarão: ค่า 0-127 เหมือนกันในแทบทุกการเข้ารหัสดังนั้นการตัดทอนค่าที่น้อยกว่า 127 ผลลัพธ์ในข้อความเดียวกัน ใส่ตัวอักษรจีนแล้วคุณจะเห็นความล้มเหลว
Mooing Duck

3
@ PedroLamarão: ค่า 128-255 ของ windows codepage 1252 (ค่าเริ่มต้นเป็นภาษาอังกฤษของ Windows) และค่า 128-255 ของ unicode ส่วนใหญ่จะเหมือนกันดังนั้นถ้าเป็น codepage ที่คุณใช้อักขระส่วนใหญ่ควรถูกตัดให้ถูกต้อง ค่า (ฉันคาดหวังทั้งหมดáและõในการทำงานฉันรู้ว่ารหัสของเราในที่ทำงานอาศัยสิ่งนี้สำหรับéซึ่งฉันจะแก้ไขในไม่ช้า)
Mooing Duck

2
มันใช้งานได้ดี MSVS 2015 และ MSVS 2017 และ MINGW / g ++ และ clang ++ ถูกกฎหมาย ++ 1.
Nikos

11

แทนที่จะใส่โลแคลและสิ่งแฟนซีทั้งหมดหากคุณรู้ว่า FACT สตริงของคุณสามารถเปลี่ยนแปลงได้เพียงทำสิ่งนี้:

#include <iostream>
#include <string>

using namespace std;

int main()
{
  wstring w(L"bla");
  string result;
  for(char x : w)
    result += x;

  cout << result << '\n';
}

ตัวอย่างสดที่นี่


2
+1 เนื่องจากเป็นโซลูชันที่ใช้งานได้ง่ายสำหรับบางสถานการณ์ (สำหรับคำนิยามหลวม ๆ ของ "งาน" ฉันอาจเพิ่ม)
กา

2
เกือบจะเหมือนกันกับโซลูชันของ namar0x0309 ซึ่งเป็น IMHO ที่สง่างามกว่ามาก แต่นั่นเป็นเพียงฉัน
onitake

ฉันเขียนโค้ดของคุณเพื่อใช้งานจริงกับการแก้ไขน้อยที่สุด ;-)
rubenvb

9
-1 ถ้าคุณมี wstring เป็นไปได้ว่าคุณกำลังเผชิญกับอักขระหลายไบต์ หากคุณรู้ว่าสตริงนั้นสามารถเปลี่ยนแปลงได้เล็กน้อยคุณจะไม่จัดการ wstring ตั้งแต่แรก มีโอกาสมากขึ้นที่คุณจะจัดการกับห้องสมุดอื่นที่คาดว่าคุณจะจัดการกับ wstring ได้อย่างถูกต้อง การตัดทอน wchars เป็นเพียงการขอร้องให้ติดตามรอยบั๊กได้ยาก นอกจากนี้คุณควรใช้ "ผลลัพธ์สตริง (w.begin (), w.end ());" หากคุณกำลังจะทำเพื่อหลีกเลี่ยงการวนซ้ำที่สามารถกระตุ้นการจัดสรรซ้ำจำนวนมาก
Kian

7

ฉันเชื่อว่าวิธีการอย่างเป็นทางการยังคงเป็นเรื่องที่ต้องทำcodecvt(คุณต้องมีการแปลภาษาที่รับรู้) เช่นเดียวกับใน

resultCode = use_facet<codecvt<char, wchar_t, ConversionState> >(locale).
  in(stateVar, scratchbuffer, scratchbufferEnd, from, to, toLimit, curPtr);

หรืออะไรทำนองนั้นฉันไม่มีรหัสทำงานอยู่ แต่ฉันไม่แน่ใจว่าวันนี้มีกี่คนที่ใช้เครื่องจักรนั้นและมีกี่คนที่ขอตัวชี้ไปยังหน่วยความจำและให้ ICU หรือห้องสมุดอื่นจัดการรายละเอียดที่เต็มไปด้วยเลือด


7

มีปัญหาสองประการเกี่ยวกับรหัส:

  1. การแปลงconst std::string s( ws.begin(), ws.end() );ไม่จำเป็นต้องแมปอักขระที่กว้างกับคู่ที่แคบได้อย่างถูกต้อง เป็นไปได้มากว่าตัวละครแต่ละตัวจะเป็นตัวพิมพ์charใหญ่
    การแก้ปัญหานี้ได้ให้ไว้แล้วในคำตอบโดย kemและเกี่ยวข้องกับnarrowฟังก์ชันของctypefacet ของ locale

  2. คุณกำลังเขียนผลลัพธ์ไปยังทั้งสองstd::coutและstd::wcoutในโปรแกรมเดียวกัน ทั้งสองcoutและwcoutเชื่อมโยงกับสตรีมเดียวกัน ( stdout) และผลลัพธ์ของการใช้สตรีมเดียวกันทั้งสองเป็นสตรีมแบบไบต์ต่อ (เช่นเดียวcout) และสตรีมแบบกว้าง (เช่นเดียวwcout) ไม่ได้ถูกกำหนดไว้
    ตัวเลือกที่ดีที่สุดคือการหลีกเลี่ยงการผสมเอาท์พุทแคบและกว้างกับสตรีม (พื้นฐาน) เดียวกัน สำหรับstdout/ cout/ wcoutคุณสามารถลองเปลี่ยนทิศทางstdoutเมื่อสลับระหว่างเอาต์พุตแบบกว้างและแคบ (หรือกลับกัน):

    #include <iostream>
    #include <stdio.h>
    #include <wchar.h>
    
    int main() {
        std::cout << "narrow" << std::endl;
        fwide(stdout, 1); // switch to wide
        std::wcout << L"wide" << std::endl;
        fwide(stdout, -1); // switch to narrow
        std::cout << "narrow" << std::endl;
        fwide(stdout, 1); // switch to wide
        std::wcout << L"wide" << std::endl;
    }

ใช่นั่นช่วยแก้ไขปัญหาด้วยการใช้ cout และ wcout
BЈовић

7

การเข้ารหัสเริ่มต้นเมื่อ:

  • Windows UTF-16
  • Linux UTF-8
  • MacOS UTF-8

รหัสนี้มีสองรูปแบบในการแปลง std :: string เป็น std :: wstring และ std :: wstring เป็น std :: string หากคุณปฏิเสธ # หากกำหนด WIN32 คุณจะได้ผลลัพธ์เดียวกัน

1. std :: string to std :: wstring

MultiByteToWideChar WinAPI

_mbstowcs_s_l

#if defined WIN32
#include <windows.h>
#endif

std::wstring StringToWideString(std::string str)
{
    if (str.empty())
    {
        return std::wstring();
    }
    size_t len = str.length() + 1;
    std::wstring ret = std::wstring(len, 0);
#if defined WIN32
    int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &str[0], str.size(), &ret[0], len);
    ret.resize(size);
#else
    size_t size = 0;
    _locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8");
    errno_t retval = _mbstowcs_s_l(&size, &ret[0], len, &str[0], _TRUNCATE, lc);
    _free_locale(lc);
    ret.resize(size - 1);
#endif
    return ret;
}

2. std :: wstring ถึง std :: string

WideCharToMultiByte WinAPI

_wcstombs_s_l

std::string WidestringToString(std::wstring wstr)
{
    if (wstr.empty())
    {
        return std::string();
    }
#if defined WIN32
    int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), NULL, 0, NULL, NULL);
    std::string ret = std::string(size, 0);
    WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), &ret[0], size, NULL, NULL);
#else
    size_t size = 0;
    _locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8");
    errno_t err = _wcstombs_s_l(&size, NULL, 0, &wstr[0], _TRUNCATE, lc);
    std::string ret = std::string(size, 0);
    err = _wcstombs_s_l(&size, &ret[0], size, &wstr[0], _TRUNCATE, lc);
    _free_locale(lc);
    ret.resize(size - 1);
#endif
    return ret;
}

3. ใน windows คุณต้องพิมพ์ Unicode โดยใช้ WinAPI

WriteConsole

#if defined _WIN32
    void WriteLineUnicode(std::string s)
    {
        std::wstring unicode = StringToWideString(s);
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL);
        std::cout << std::endl;
    }

    void WriteUnicode(std::string s)
    {
        std::wstring unicode = StringToWideString(s);
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL);
    }

    void WriteLineUnicode(std::wstring ws)
    {
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL);
        std::cout << std::endl;
    }

    void WriteUnicode(std::wstring ws)
    {
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL);
    }

4. ในโปรแกรมหลัก

#if defined _WIN32
int wmain(int argc, WCHAR ** args)
#else
int main(int argc, CHAR ** args)
#endif
{
    std::string source = u8"ÜüΩωЙ你月曜日\na🐕èéøÞǽлљΣæča🐕🐕";
    std::wstring wsource = L"ÜüΩωЙ你月曜日\na🐕èéøÞǽлљΣæča🐕🐕";

    WriteLineUnicode(L"@" + StringToWideString(source) + L"@");
    WriteLineUnicode("@" + WidestringToString(wsource) + "@");
    return EXIT_SUCCESS;
}

5. ในที่สุดคุณต้องมีประสิทธิภาพและการสนับสนุนที่สมบูรณ์สำหรับ unicode chars ใน console ผมขอแนะนำให้ConEmuและตั้งเป็นสถานีเริ่มต้นบน Windows คุณต้องขอ Visual Studio กับ ConEmu โปรดจำไว้ว่าไฟล์ exe ของ Visual Studio เป็นdevenv.exe

ทดสอบกับ Visual Studio 2017 ด้วย VC ++ มาตรฐาน = C ++ 17

ผลลัพธ์

result1


6

คุณอาจใช้วิธีแคบ ๆ ของ ctype facet โดยตรง:

#include <clocale>
#include <locale>
#include <string>
#include <vector>

inline std :: string แคบ (std :: wstring const & ข้อความ)
{
    std :: loc loc const loc ("");
    wchar_t const * จาก = text.c_str ();
    std :: size_t const len ​​= text.size ();
    std :: vector <char> บัฟเฟอร์ (len + 1);
    std :: use_facet <std :: ctype <wchar_t>> (loc) .narrow (จาก, จาก + len, '_', & บัฟเฟอร์ [0]);
    return std :: string (& buffer [0], & buffer [len]);
}

6

ในขณะที่เขียนคำตอบนี้การค้นหาหมายเลขหนึ่งของ Google สำหรับ "การแปลงสตริง wstring" จะทำให้คุณอยู่ในหน้านี้ คำตอบของฉันแสดงวิธีแปลงสตริงเป็น wstring แม้ว่านี่ไม่ใช่คำถามจริงและฉันควรลบคำตอบนี้ แต่ถือว่าเป็นรูปแบบที่ไม่ดี คุณอาจต้องการข้ามไปที่คำตอบ StackOverflowซึ่งตอนนี้ได้รับการจัดอันดับสูงกว่าหน้านี้


นี่คือวิธีในการรวมสตริง, wstring และค่าคงที่สตริงผสมกับ wstring ใช้คลาส wstringstream

#include <sstream>

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

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

13
นี้ไม่ใช่การแปลงสตริงเป็นสตริง
poitroae

1
@Michael ช่วยอธิบายหน่อยได้ไหม? สิ่งนี้ไม่ถูกต้อง ความคิดเห็นของคุณไม่มีประโยชน์หากไม่มีรายละเอียดเพิ่มเติม
เนท

1
นี่คือสตริงการแปลง wstring เช่นตรงข้ามกับคำถาม
Jeff McClintock

4

นอกจากการแปลงประเภทแล้วคุณควรตระหนักถึงรูปแบบที่แท้จริงของสตริงด้วย

เมื่อทำการคอมไพล์สำหรับชุดอักขระแบบหลายไบต์ Visual Studio และ Win API ถือว่าเป็น UTF8 (จริง ๆ แล้วการเข้ารหัส windows ซึ่งเป็นWindows-28591 )
เมื่อรวบรวมชุดอักขระ Unicode Visual Studio และ Win API จะถือว่าเป็น UTF16

ดังนั้นคุณต้องแปลงสตริงจากรูปแบบ UTF16 เป็น UTF8 ด้วยและไม่เพียงแปลงเป็น std :: string
สิ่งนี้จะกลายเป็นสิ่งจำเป็นเมื่อทำงานกับรูปแบบหลายอักขระเช่นภาษาที่ไม่ใช่ละติน

ความคิดที่จะตัดสินใจว่าstd::wstring มักจะแสดงให้เห็นถึงUTF16
และstd::string มักจะแสดงให้เห็นถึงUTF8

คอมไพเลอร์ไม่ได้บังคับใช้ แต่เป็นนโยบายที่ดีกว่า สังเกตคำนำหน้าสตริงที่ฉันใช้เพื่อกำหนด UTF16 ( L ) และ UTF8 ( u8 )

ในการแปลงระหว่าง 2 ประเภทคุณควรใช้: std :: codecvt_utf8_utf16 <wchar_t>

#include <string>

#include <codecvt>

int main()
{

    std::string original8 = u8"הלו";

    std::wstring original16 = L"הלו";

    //C++11 format converter
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;

    //convert to UTF8 and std::string
    std::string utf8NativeString = convert.to_bytes(original16);

    std::wstring utf16NativeString = convert.from_bytes(original8);

    assert(utf8NativeString == original8);
    assert(utf16NativeString == original16);

    return 0;
}

3

ในกรณีของฉันฉันต้องใช้อักขระหลายไบต์ (MBCS) และฉันต้องการใช้ std :: string และ std :: wstring และไม่สามารถใช้ c ++ 11 ได้ ดังนั้นฉันจึงใช้ mbstowcs และ wcstombs

ฉันทำฟังก์ชั่นเดียวกันกับการใช้ใหม่ลบ [] แต่มันจะช้ากว่านี้

วิธีนี้จะช่วยให้วิธีการ: แปลงระหว่างประเภทสตริงที่หลากหลาย

แก้ไข

อย่างไรก็ตามในกรณีที่แปลงเป็นสตริงและสตริงแหล่งที่มาไม่ใช่สตริงตัวอักษรและหลายไบต์สตริงจะไม่ทำงาน ดังนั้นฉันเปลี่ยน wcstombs เป็น WideCharToMultiByte

#include <string>

std::wstring get_wstr_from_sz(const char* psz)
{
    //I think it's enough to my case
    wchar_t buf[0x400];
    wchar_t *pbuf = buf;
    size_t len = strlen(psz) + 1;

    if (len >= sizeof(buf) / sizeof(wchar_t))
    {
        pbuf = L"error";
    }
    else
    {
        size_t converted;
        mbstowcs_s(&converted, buf, psz, _TRUNCATE);
    }

    return std::wstring(pbuf);
}

std::string get_string_from_wsz(const wchar_t* pwsz)
{
    char buf[0x400];
    char *pbuf = buf;
    size_t len = wcslen(pwsz)*2 + 1;

    if (len >= sizeof(buf))
    {
        pbuf = "error";
    }
    else
    {
        size_t converted;
        wcstombs_s(&converted, buf, pwsz, _TRUNCATE);
    }

    return std::string(pbuf);
}

แก้ไขเพื่อใช้ 'MultiByteToWideChar' แทน 'wcstombs'

#include <Windows.h>
#include <boost/shared_ptr.hpp>
#include "string_util.h"

std::wstring get_wstring_from_sz(const char* psz)
{
    int res;
    wchar_t buf[0x400];
    wchar_t *pbuf = buf;
    boost::shared_ptr<wchar_t[]> shared_pbuf;

    res = MultiByteToWideChar(CP_ACP, 0, psz, -1, buf, sizeof(buf)/sizeof(wchar_t));

    if (0 == res && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        res = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);

        shared_pbuf = boost::shared_ptr<wchar_t[]>(new wchar_t[res]);

        pbuf = shared_pbuf.get();

        res = MultiByteToWideChar(CP_ACP, 0, psz, -1, pbuf, res);
    }
    else if (0 == res)
    {
        pbuf = L"error";
    }

    return std::wstring(pbuf);
}

std::string get_string_from_wcs(const wchar_t* pcs)
{
    int res;
    char buf[0x400];
    char* pbuf = buf;
    boost::shared_ptr<char[]> shared_pbuf;

    res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, buf, sizeof(buf), NULL, NULL);

    if (0 == res && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, NULL, 0, NULL, NULL);

        shared_pbuf = boost::shared_ptr<char[]>(new char[res]);

        pbuf = shared_pbuf.get();

        res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, pbuf, res, NULL, NULL);
    }
    else if (0 == res)
    {
        pbuf = "error";
    }

    return std::string(pbuf);
}

ฉันจะใช้ "wcstombs_s" กับ gcc 4.8 ได้อย่างไร เพราะฉันเห็นว่าเป็นคุณสมบัติ C ++ 11
Cristian

@cristian คุณสามารถใช้รุ่นนี้ "ไม่ปลอดภัย" ของฟังก์ชั่นwcstombs()นี้
Vizor

3

โซลูชันนี้ได้รับแรงบันดาลใจในโซลูชันของ dk123แต่ใช้ตัวแปลงสัญญาณที่ขึ้นกับโลแคล ผลลัพธ์อยู่ในสตริงที่เข้ารหัสโลแคลแทน UTF-8 (หากไม่ได้ตั้งเป็นโลแคล):

std::string w2s(const std::wstring &var)
{
   static std::locale loc("");
   auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
   return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).to_bytes(var);
}

std::wstring s2w(const std::string &var)
{
   static std::locale loc("");
   auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
   return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).from_bytes(var);
}

ฉันค้นหามัน แต่ฉันหามันไม่เจอ ในที่สุดฉันก็พบว่าฉันสามารถได้รับแง่มุมที่ถูกต้องจากstd::localeใช้std::use_facet()ฟังก์ชั่นด้วยชื่อที่ถูก หวังว่านี่จะช่วยได้


สิ่งที่มีประโยชน์ (ถ้ามี) ของการแปลงด้วยแง่มุมที่ขึ้นอยู่กับสถานที่?
Marc.2377

หากคุณทำงานกับสตริงจากระบบจากอินพุตคอนโซลเช่น
Vizor

1

ในกรณีที่คนอื่นสนใจ: ฉันต้องการชั้นเรียนที่สามารถใช้แทนกันได้ทุกที่stringหรือwstringเป็นที่คาดหวัง ชั้นต่อไปconvertible_stringขึ้นอยู่กับวิธีการแก้ปัญหา dk123 ของสามารถเริ่มต้นได้ด้วยทั้งstring, char const*, wstringหรือwchar_t const*และสามารถกำหนดให้โดยปริยายหรือแปลงเป็นอย่างใดอย่างหนึ่งstringหรือwstring(เพื่อให้สามารถผ่านเข้าสู่ฟังก์ชั่นที่ใช้อย่างใดอย่างหนึ่ง)

class convertible_string
{
public:
    // default ctor
    convertible_string()
    {}

    /* conversion ctors */
    convertible_string(std::string const& value) : value_(value)
    {}
    convertible_string(char const* val_array) : value_(val_array)
    {}
    convertible_string(std::wstring const& wvalue) : value_(ws2s(wvalue))
    {}
    convertible_string(wchar_t const* wval_array) : value_(ws2s(std::wstring(wval_array)))
    {}

    /* assignment operators */
    convertible_string& operator=(std::string const& value)
    {
        value_ = value;
        return *this;
    }
    convertible_string& operator=(std::wstring const& wvalue)
    {
        value_ = ws2s(wvalue);
        return *this;
    }

    /* implicit conversion operators */
    operator std::string() const { return value_; }
    operator std::wstring() const { return s2ws(value_); }
private:
    std::string value_;
};

1
ผมค่อนข้างจะเก็บstd::wstringในชั้นเรียนกว่าการจัดเก็บstd::stringและทำแปลงไปเมื่อมีความจำเป็นที่จะได้รับstd::wstring std::wstringเพราะstd::wstringค่อนข้างเร็วกว่าstd::stringและเข้ากันได้ดีกว่า std::stringแม้จะสิ้นเปลืองหน่วยความจำมากกว่า
0xAA55

0
#include <boost/locale.hpp>
namespace lcv = boost::locale::conv;

inline std::wstring fromUTF8(const std::string& s)
{ return lcv::utf_to_utf<wchar_t>(s); }

inline std::string toUTF8(const std::wstring& ws)
{ return lcv::utf_to_utf<char>(ws); }

-1

ฉันใช้ด้านล่างเพื่อแปลง wstring เป็นสตริง

std::string strTo;
char *szTo = new char[someParam.length() + 1];
szTo[someParam.size()] = '\0';
WideCharToMultiByte(CP_ACP, 0, someParam.c_str(), -1, szTo, (int)someParam.length(), NULL, NULL);
strTo = szTo;
delete szTo;

ดูเหมือนว่าคุณจะไม่มีส่วนหัวมาตรฐาน ( <string>) และคำจำกัดความสำหรับWideCharToMultiByte()- นั่นคือเสื้อคลุมบางส่วนstd::wctomb()หรือไม่?
Toby Speight

-3
// Embarcadero C++ Builder 

// convertion string to wstring
string str1 = "hello";
String str2 = str1;         // typedef UnicodeString String;   -> str2 contains now u"hello";

// convertion wstring to string
String str2 = u"hello";
string str1 = UTF8string(str2).c_str();   // -> str1 contains now "hello"

3
โปรดอธิบายสิ่งที่ทำในคำตอบของคุณไม่เช่นนั้นอาจถูกลบ
CodeFanatic

1
ฟังก์ชัน UTF8string มาจากไหน
Jean-Christophe Blanchard
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.