2011-08-22 35 views
16

Nếu tôi có UTF-8 std::string làm cách nào để chuyển đổi nó sang UTF-16 std::wstring? Thực ra, tôi muốn so sánh hai từ tiếng Ba Tư.Làm thế nào để chuyển đổi UTF-8 std :: chuỗi thành UTF-16 std :: wstring?

+0

Xem http://stackoverflow.com/questions/148403/utf8-to-from-wide-char-conversion-in-stl trong số những người khác. –

+0

có thể trùng lặp của [làm thế nào tôi có thể so sánh chuỗi utf8 chẳng hạn như từ tiếng Ba Tư trong c + +?] (Http://stackoverflow.com/questions/7141417/how-can-i-compare-utf8-string-such-as-persian- word-in-c) hoặc [this] (http://stackoverflow.com/questions/7141260/compare-stdwstring-and-stdstring). –

Trả lời

19

Dưới đây là một số mã. Chỉ được thử nghiệm nhẹ và có thể có một số cải tiến. Gọi hàm này để chuyển đổi chuỗi UTF-8 thành chuỗi ký tự UTF-16. Nếu nó cho rằng chuỗi đầu vào không phải là UTF-8 thì nó sẽ ném một ngoại lệ, ngược lại nó trả về chuỗi ký tự UTF-16 tương đương.

std::wstring utf8_to_utf16(const std::string& utf8) 
{ 
    std::vector<unsigned long> unicode; 
    size_t i = 0; 
    while (i < utf8.size()) 
    { 
     unsigned long uni; 
     size_t todo; 
     bool error = false; 
     unsigned char ch = utf8[i++]; 
     if (ch <= 0x7F) 
     { 
      uni = ch; 
      todo = 0; 
     } 
     else if (ch <= 0xBF) 
     { 
      throw std::logic_error("not a UTF-8 string"); 
     } 
     else if (ch <= 0xDF) 
     { 
      uni = ch&0x1F; 
      todo = 1; 
     } 
     else if (ch <= 0xEF) 
     { 
      uni = ch&0x0F; 
      todo = 2; 
     } 
     else if (ch <= 0xF7) 
     { 
      uni = ch&0x07; 
      todo = 3; 
     } 
     else 
     { 
      throw std::logic_error("not a UTF-8 string"); 
     } 
     for (size_t j = 0; j < todo; ++j) 
     { 
      if (i == utf8.size()) 
       throw std::logic_error("not a UTF-8 string"); 
      unsigned char ch = utf8[i++]; 
      if (ch < 0x80 || ch > 0xBF) 
       throw std::logic_error("not a UTF-8 string"); 
      uni <<= 6; 
      uni += ch & 0x3F; 
     } 
     if (uni >= 0xD800 && uni <= 0xDFFF) 
      throw std::logic_error("not a UTF-8 string"); 
     if (uni > 0x10FFFF) 
      throw std::logic_error("not a UTF-8 string"); 
     unicode.push_back(uni); 
    } 
    std::wstring utf16; 
    for (size_t i = 0; i < unicode.size(); ++i) 
    { 
     unsigned long uni = unicode[i]; 
     if (uni <= 0xFFFF) 
     { 
      utf16 += (wchar_t)uni; 
     } 
     else 
     { 
      uni -= 0x10000; 
      utf16 += (wchar_t)((uni >> 10) + 0xD800); 
      utf16 += (wchar_t)((uni & 0x3FF) + 0xDC00); 
     } 
    } 
    return utf16; 
} 
+1

cảm ơn bạn! cảm ơn bạn! nó đã làm việc ... Tôi không thể tin được :) cảm ơn bạn đã dành thời gian của bạn john – aliakbarian

+0

Thật vui vì nó đã giúp ích. Nó thực sự chỉ là vấn đề đặt câu hỏi đúng. Có rất nhiều kiến ​​thức trên diễn đàn này, nhưng người mới thường không thể truy cập kiến ​​thức đó bởi vì họ không biết phải hỏi gì. – john

+0

cảm ơn bạn một lần nữa! :-) – aliakbarian

2

Có một số liên quan Q & A herehere đáng để đọc.

Về cơ bản, bạn cần phải chuyển đổi chuỗi thành định dạng chung - tùy chọn của tôi luôn chuyển đổi thành UTF-8, nhưng số dặm của bạn có thể cảnh giác.

Đã có rất nhiều phần mềm được viết để thực hiện việc chuyển đổi - chuyển đổi là straigth chuyển tiếp và có thể được viết trong một vài giờ - tuy nhiên tại sao không pick up something already done such as the UTF-8 CPP

+0

Nếu bạn chỉ sử dụng Windows: http://msdn.microsoft.com/en-us/library/dd319072(v=VS.85).aspx. Nếu không, hãy sử dụng thư viện di động. –

2

Trang này cũng có vẻ hữu ích: http://www.codeproject.com/KB/string/UtfConverter.aspx

Trong phần bình luận của trang đó, cũng có một số gợi ý thú vị cho nhiệm vụ này như:

// Get en ASCII std::string from anywhere 
std::string sLogLevelA = "Hello ASCII-world!"; 

std::wstringstream ws; 
ws << sLogLevelA.c_str(); 
std::wstring sLogLevel = ws.str(); 

Hoặc

// To std::string: 
str.assign(ws.begin(), ws.end()); 
// To std::wstring 
ws.assign(str.begin(), str.end()); 

Mặc dù tôi không chắc chắn về tính hợp lệ của các cách tiếp cận này ...

14

Đây là cách bạn làm điều đó với C++ 11:

std::string str = "your string in utf8"; 
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>> converter; 
std::wstring wstr = converter.from_bytes(str); 

Và đây là những tiêu đề bạn cần:

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

Một ví dụ hoàn chỉnh hơn có sẵn ở đây: http://en.cppreference.com/w/cpp/locale/wstring_convert/from_bytes

+0

Câu trả lời hay, cảm ơn! ... nhưng hãy làm theo ví dụ tại cppreference.com. 'wchar_t' không phải là kiểu 16 bit trên các hệ điều hành khác với Windows. Bạn cần sử dụng 'char16_t' để thay thế. –

+0

@CrisLuengo cảm ơn! Tôi đã cập nhật câu trả lời để sử dụng 'char16_t'. –

+2

Không hoạt động với g ++ 6.2 hoặc clang ++ 3.8 trên lubuntu 16.04 –

Các vấn đề liên quan