Làm thế nào để chuyển đổi chuỗi thành chuỗi?


204

Câu hỏi là làm thế nào để chuyển đổi chuỗi thành chuỗi?

Tôi có ví dụ tiếp theo:

#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;
}

đầu ra với dòng nhận xét là:

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

nhưng không có chỉ là:

std::wstring =    Hello

Có bất cứ điều gì sai trong ví dụ? Tôi có thể thực hiện chuyển đổi như trên không?

BIÊN TẬP

Ví dụ mới (có tính đến một số câu trả lời) là

#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;
}

Đầu ra là:

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

do đó, chuỗi dòng không thể được sử dụng để chuyển đổi chuỗi thành chuỗi.


4
Làm thế nào bạn có thể hỏi câu hỏi này mà không chỉ định mã hóa?
David Heffernan

5
@tenfour: Tại sao lại sử dụng std::wstring? stackoverflow.com/questions/1049947/ từ
dalle

11
@dalle Nếu bạn có dữ liệu đã được mã hóa bằng UTF-16, việc UTF-16 có được coi là có hại hay không là một phần. Và với những gì đáng giá, tôi không nghĩ bất kỳ hình thức chuyển đổi nào cũng có hại; Điều có hại là mọi người nghĩ rằng họ hiểu Unicode khi thực tế họ không biết.
David Heffernan

2
Liệu nó có phải là một giải pháp đa nền tảng?
ali_bahoo

2
@dalle c ++ tiêu chuẩn không đề cập đến utf dưới bất kỳ hình thức nào (utf-8 hoặc utf-16). Có một liên kết nơi nó nói tại sao utf-16 không thể được mã hóa bằng chuỗi?
BЈовић

Câu trả lời:


31

Đây là một giải pháp được thực hiện dựa trên các đề xuất khác:

#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;
  }
}

Điều này thường sẽ làm việc cho Linux, nhưng sẽ tạo ra vấn đề trên Windows.


@Phillip: phần nào của mã phụ thuộc vào ngôn ngữ c? là std::setlocale(LC_ALL, "");thực sự cần thiết?
smerlin

2
sử dụng std::wcout.imbue(locale)nên thực hiện công việc tốt, và nó có lợi ích là nó không thay đổi bất kỳ trạng thái toàn cầu nào.
smerlin

32
Các std::wstring_converttừ C ++ 11 kết thúc tốt đẹp lên rất nhiều tiếng ồn này.
Cubbi

7
@Philipp, ý bạn là gì "sẽ tạo ra vấn đề trên Windows"? Loại vấn đề nào?
Gili

1
Đoạn mã trên cho (như được sao chép) mang lại cho tôi một *** glibc detected *** test: malloc(): smallbin double linked list corrupted: 0x000000000180ea30 ***bản linux 64-bit (gcc 4.7.3). Bất cứ ai khác trải nghiệm điều này?
hogliux

312

Như Cubbi đã chỉ ra trong một trong những ý kiến, std::wstring_convert(C ++ 11) cung cấp một giải pháp đơn giản gọn gàng (bạn cần #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 );

Tôi đã sử dụng kết hợp wcstombsvà phân bổ / giải quyết bộ nhớ tẻ nhạt trước khi tôi bắt gặp điều này.

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

cập nhật (2013.11.28)

Một lớp lót có thể được nêu như vậy (Cảm ơn bạn đã bình luận của bạn):

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

Các hàm Wrapper có thể được nêu như vậy: (Cảm ơn ArmanSchwarz vì bình luận của bạn)

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);
}

Lưu ý: có một số tranh cãi về việc string/ wstringnên được chuyển đến các chức năng dưới dạng tham chiếu hoặc dưới dạng chữ (do C ++ 11 và các bản cập nhật trình biên dịch). Tôi sẽ để lại quyết định cho người thực hiện, nhưng nó đáng để biết.

Lưu ý: Tôi đang sử dụng std::codecvt_utf8mã ở trên, nhưng nếu bạn không sử dụng UTF-8, bạn cần thay đổi mã đó thành mã hóa phù hợp bạn đang sử dụng:

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


25
Vui lòng +1 : đây là cách chuẩn C ++ chính thức để thực hiện chuyển đổi chuỗi. Bạn cũng có thể sử dụng from_bytes để chuyển đổi theo cách khác. Bởi vì cá nhân tôi thích một lớp lót, đây là phiên bản của tôi:std::wstring str = std::wstring_convert<std::codecvt_utf<wchar_t>>().from_bytes("some string");
Guss 11/11/13

7
Có vẻ như en.cppreference.com/w/cpp/header/codecvt không khả dụng kể từ g ++ 4.8.2. Hai phương thức s2ws và ws2s hiện không hoạt động trong linux
Begui

5
Có vẻ như điều này không được chấp nhận ( stackoverflow.com/a/42946556/211176 ). Trình biên dịch của tôi ném lỗi khi tôi cố chạy mã này
adam_0


5
Đối với bất kỳ ai lo lắng về C ++ 17 và khả năng tương thích hơn nữa (do không dùng nữa), hãy xem: stackoverflow.com/a/18597384/6205379
Timo

128

Giải pháp từ: http://forums.devshed.com/c-programming-42/wopes-to-opes-444006.html

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

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

Cẩn thận rằng có không chuyển đổi bộ ký tự xảy ra ở đây cả. Điều này chỉ đơn giản là gán mỗi lần lặp wchar_tcho một char- một chuyển đổi cắt ngắn. Nó sử dụng std :: string c'tor :

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

Như đã nêu trong các ý kiến:

các giá trị 0-127 giống hệt nhau trong hầu hết mọi mã hóa, do đó, việc cắt bớt các giá trị có ít hơn 127 kết quả trong cùng một văn bản. Đặt một nhân vật Trung Quốc và bạn sẽ thấy sự thất bại.

-

các giá trị 128-255 của windows codepage 1252 (mặc định của Windows English) và các giá trị 128-255 của unicode hầu như giống nhau, vì vậy nếu đó là cách mà bạn sử dụng hầu hết các ký tự đó nên được cắt bớt thành các giá trị chính xác. (Tôi hoàn toàn mong đợi á và õ hoạt động. Tôi biết mã của chúng tôi tại nơi làm việc dựa trên điều này cho é, mà tôi sẽ sớm sửa)

Và lưu ý rằng các điểm mã trong phạm vi 0x80 - 0x9Ftrong Win1252 sẽ không hoạt động. Điều này bao gồm , œ, ž, Ÿ, ...


2
Kỳ lạ thay, điều này hoạt động trên Visual Studio 10. Điều gì đang xảy ra? Điều này sẽ gây ra một sự cắt xén từ wchar_t đến char cho tất cả các phần tử của chuỗi gốc.
Pedro Lamarão

6
... khi nó đi đến bất kỳ nhân vật phi Latin nào.
JavaRunner

8
@ PedroLamarão: các giá trị 0-127 giống hệt nhau trong hầu hết mọi mã hóa, do đó, các giá trị bị cắt bớt đều nhỏ hơn 127 kết quả trong cùng một văn bản. Đặt một nhân vật Trung Quốc và bạn sẽ thấy sự thất bại.
Vịt Mooing

3
@ PedroLamarão: các giá trị 128-255 của windows codepage 1252 (mặc định của Windows English) và các giá trị 128-255 của unicode hầu như giống nhau, vì vậy, nếu đó là cách mã hóa bạn sử dụng hầu hết các ký tự đó sẽ bị cắt cụt các giá trị. (Tôi hoàn toàn mong đợi á và õ hoạt động, tôi biết mã của chúng tôi tại nơi làm việc dựa trên điều này cho é, mà tôi sẽ sớm sửa)
Mooing Duck

2
Điều này làm việc tuyệt vời. MSVS 2015 và MSVS 2017 và MINGW / g ++ và clang ++. Hợp pháp ++ 1.
Nikos

11

Thay vì bao gồm miền địa phương và tất cả những thứ ưa thích đó, nếu bạn biết với SỰ THẬT, chuỗi của bạn có thể chuyển đổi, chỉ cần làm điều này:

#include <iostream>
#include <string>

using namespace std;

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

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

Ví dụ trực tiếp tại đây


2
+1 vì đó là một giải pháp đơn giản phù hợp với một số tình huống (đối với định nghĩa lỏng lẻo về "công việc", tôi có thể thêm vào).
quạ

2
Gần giống như giải pháp của namar0x0309, IMHO thanh lịch hơn nhiều. Nhưng đó chỉ là tôi.
bắt đầu

Tôi đã cải thiện mã của bạn để thực sự hoạt động với sửa đổi tối thiểu ;-)
rubenvb

9
-1 Nếu bạn có một chuỗi, có khả năng bạn đang xử lý các ký tự đa nhân. Nếu bạn có thể biết chuỗi có thể chuyển đổi tầm thường, bạn sẽ không xử lý chuỗi ở vị trí đầu tiên. Nhiều khả năng, bạn đang làm việc với một thư viện khác hy vọng bạn sẽ xử lý đúng chuỗi. Cắt xén các wchars chỉ là cầu xin một lỗi khó theo dõi sau này. Ngoài ra, bạn nên sử dụng "chuỗi kết quả (w.begin (), w.end ());" nếu bạn định làm điều đó, để tránh một vòng lặp có thể kích hoạt nhiều sự phân bổ lại.
Kian

7

Tôi tin rằng cách chính thức vẫn là đi codecvtcác khía cạnh thorugh (bạn cần một số loại dịch thuật nhận biết bản địa), như trong

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

hoặc một cái gì đó tương tự, tôi không có mã làm việc nằm xung quanh. Nhưng tôi không chắc có bao nhiêu người ngày nay sử dụng máy móc đó và bao nhiêu người chỉ cần yêu cầu con trỏ vào bộ nhớ và để ICU hoặc một số thư viện khác xử lý các chi tiết chính.


7

Có hai vấn đề với mã:

  1. const std::string s( ws.begin(), ws.end() );Không cần phải chuyển đổi để ánh xạ chính xác các ký tự rộng sang đối tác hẹp của chúng. Nhiều khả năng, mỗi nhân vật rộng sẽ chỉ là typecast char.
    Việc giải quyết vấn đề này đã được đưa ra trong câu trả lời của kem và liên quan đến narrowchức năng của ctypekhía cạnh địa phương .

  2. Bạn đang viết đầu ra cho cả hai std::coutstd::wcouttrong cùng một chương trình. Cả hai coutwcoutđược liên kết với cùng một luồng ( stdout) và kết quả của việc sử dụng cùng một luồng cả hai luồng theo hướng byte (cũng như luồng cout) và luồng định hướng rộng (như wcoutkhông) không được xác định.
    Tùy chọn tốt nhất là tránh trộn lẫn đầu ra hẹp và rộng vào cùng một luồng (bên dưới). Đối với stdout/ cout/ wcout, bạn có thể thử chuyển đổi hướng stdoutkhi chuyển giữa đầu ra rộng và hẹp (hoặc ngược lại):

    #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;
    }

Vâng, điều đó khắc phục vấn đề với việc sử dụng cout và wcout.
BЈовић

7

Mã hóa mặc định trên:

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

Mã này có hai hình thức để chuyển đổi std :: string thành std :: wopes và std :: wopes thành std :: string. Nếu bạn phủ nhận #if được xác định WIN32, bạn sẽ nhận được kết quả tương tự.

1. std :: chuỗi to std :: chuỗi

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 :: chuỗi đến std :: chuỗi

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. Trên cửa sổ, bạn cần in unicode, sử dụng WinAPI.

Viết

#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. Trên chương trình chính.

#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. Cuối cùng, bạn cần một sự hỗ trợ mạnh mẽ và đầy đủ cho các ký tự unicode trong bảng điều khiển. Tôi khuyên dùng ConEmu và đặt làm thiết bị đầu cuối mặc định trên Windows . Bạn cần nối Visual Studio với ConEmu. Hãy nhớ rằng tệp exe của Visual Studio là devenv.exe

Đã thử nghiệm trên Visual Studio 2017 với VC ++; std = c ++ 17.

Kết quả

Kết quả1


6

Bạn cũng có thể chỉ cần sử dụng trực tiếp phương thức hẹp của ctype facet:

#inc loại <clocale>
#include <miền địa phương>
#include <chuỗi>
#include <vector>

nội tuyến std :: chuỗi hẹp (std :: w chuỗi const & văn bản)
{
    std :: locale const loc ("");
    wchar_t const * from = text.c_str ();
    std :: size_t const len ​​= text.size ();
    std :: vector <char> đệm (len + 1);
    std :: use_facet <std :: ctype <wchar_t >> (loc) .narrow (từ, từ + len, '_', & đệm [0]);
    return std :: string (& buffer [0], & buffer [len]);
}

6

Tại thời điểm viết câu trả lời này, tìm kiếm số một trên google cho "chuyển đổi chuỗi chuỗi" sẽ đưa bạn đến trang này. Câu trả lời của tôi cho thấy cách chuyển đổi chuỗi thành chuỗi, mặc dù đây KHÔNG phải là câu hỏi thực sự và tôi có lẽ nên xóa câu trả lời này nhưng đó được coi là hình thức xấu. Bạn có thể muốn chuyển đến câu trả lời StackOverflow này , hiện được xếp hạng cao hơn trang này.


Đây là một cách để kết hợp các hằng chuỗi, chuỗi và chuỗi hỗn hợp thành chuỗi. Sử dụng lớp dây.

#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
Đây không phải là chuyển đổi chuỗi thành chuỗi
poitroae

1
@Michael Bạn có thể giải thích? Điều này là không chính xác? Nhận xét của bạn không hữu ích nếu không có thêm chi tiết.
Nate

1
đây là một chuỗi chuyển đổi chuỗi tức là ngược lại với câu hỏi
Jeff McClintock

4

Bên cạnh việc chỉ chuyển đổi các loại, bạn cũng nên ý thức về định dạng thực của chuỗi.

Khi biên dịch cho Bộ ký tự nhiều byte Visual Studio và Win API giả định UTF8 (Trên thực tế, mã hóa windows là Windows-28591 ).
Khi biên dịch cho bộ ký tự Unicode, Visual studio và Win API giả định UTF16.

Vì vậy, bạn cũng phải chuyển đổi chuỗi từ định dạng UTF16 sang định dạng UTF8, và không chỉ chuyển đổi sang chuỗi std ::.
Điều này sẽ trở nên cần thiết khi làm việc với các định dạng đa ký tự như một số ngôn ngữ phi Latin.

Ý tưởng là quyết định std::wstring luôn đại diện cho UTF16 .
std::string luôn đại diện cho UTF8 .

Điều này không được thực thi bởi trình biên dịch, đó là một chính sách tốt hơn để có. Lưu ý các tiền tố chuỗi tôi sử dụng để xác định UTF16 ( L ) và UTF8 ( u8 ).

Để chuyển đổi giữa 2 loại, bạn nên sử dụng: 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

Trong trường hợp của tôi, tôi phải sử dụng ký tự đa nhân (MBCS) và tôi muốn sử dụng std :: string và std :: wopes. Và không thể sử dụng c ++ 11. Vì vậy, tôi sử dụng mbstowcs và wcstombs.

Tôi thực hiện chức năng tương tự với việc sử dụng mới, xóa [], nhưng nó chậm hơn thế này.

Điều này có thể giúp Làm thế nào để: Chuyển đổi giữa các loại chuỗi khác nhau

BIÊN TẬP

Tuy nhiên, trong trường hợp chuyển đổi thành chuỗi và chuỗi nguồn không có bảng chữ cái và chuỗi nhiều byte, nó không hoạt động. Vì vậy, tôi thay đổi wcstombs thành 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);
}

EDIT để sử dụng 'MultiByteToWideChar' thay vì '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);
}

Làm cách nào tôi có thể sử dụng "wcstombs_s" với gcc 4.8? Bởi vì tôi thấy đó là tính năng C ++ 11.
cristian

@cristian Bạn có thể sử dụng phiên bản "không an toàn" của chức năng này wcstombs().
Vizor

3

Giải pháp này được lấy cảm hứng từ giải pháp của dk123 , nhưng sử dụng khía cạnh codecvt phụ thuộc miền địa phương. Kết quả là trong chuỗi được mã hóa miền địa phương thay vì UTF-8 (nếu nó không được đặt là miền địa phương):

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);
}

Tôi đã tìm kiếm nó, nhưng tôi không thể tìm thấy nó. Cuối cùng tôi thấy rằng tôi có thể có được khía cạnh đúng từ std::localeviệc sử dụng std::use_facet()hàm với tên chữ đúng. Hi vọng điêu nay co ich.


Vizor, những lợi thế (nếu có) của việc chuyển đổi với khía cạnh phụ thuộc địa phương là gì?
Marc.2377

Nếu bạn làm việc với các chuỗi từ hệ thống, từ đầu vào giao diện điều khiển chẳng hạn.
Vizor

1

Trong trường hợp bất kỳ ai khác quan tâm: Tôi cần một lớp có thể được sử dụng thay thế cho nhau ở bất cứ nơi nào stringhoặc wstringdự kiến. Lớp sau convertible_string, dựa trên giải pháp dk123 của , có thể được khởi tạo với một trong hai một string, char const*,wstring hay wchar_t const*và có thể được gán cho bằng hoặc ngầm chuyển đổi sang hoặc là một stringhoặc wstring(như vậy có thể được thông qua vào một chức năng mà phải mất một trong hai).

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
Tôi thà lưu trữ một std::wstringtrong lớp, hơn là lưu trữ std::stringvà thực hiện chuyển đổi std::wstringkhi cần để có được một std::wstring. Bởi vì std::wstringcó phần nhanh hơn std::stringvà nó tương thích tốt hơn. Thậm chí nó còn tiêu tốn nhiều bộ nhớ hơn 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

Tôi đang sử dụng dưới đây để chuyển đổi chuỗi thành chuỗi.

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;

Bạn dường như đang thiếu một tiêu đề tiêu chuẩn ( <string>) và một định nghĩa cho WideCharToMultiByte()- đó có phải là một số trình bao bọc std::wctomb()không?
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
vui lòng giải thích những gì ure đang làm trong câu trả lời của bạn, nếu không nó có thể bị xóa
CodeFanatic

1
Hàm UTF8 chuỗi đến từ đâu?
Jean-Barshe Blanchard
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.