ubuntu14.04中使用wxWidgets,中文无法正常显示

  最近一直在忙着把之前完成的一个wxWidgets程序从windows环境迁移到Ubuntu环境下,在迁移过程中遇到了很多奇怪的问题,有些解决了,有些还没有解决。中文是中文程序迁移到ubuntu上最核心的问题,虽然在wxWidgets文档中说了wxString是用unicode码存储数据的,使用FromUTF8 方法可以顺利的从UTF8格式的中文中读取字符,但是实际经我验证这种方法是无效的(测试环境 Ubuntu14.04  原版为英文 en_US.utf8   后来修改locale为 zh_CN.utf8).

在翻阅资料的时候我看到了这几段化。

wxString::wxString ( const std::string &  str )  

Constructs a string from str using the using the current locale encoding to convert it to Unicode (wxConvLibc).

See also
ToStdString()

std::string wxString::ToStdString (   ) const

Return the string as an std::string in current locale encoding.

Note that if the conversion of (Unicode) string contents to the current locale fails, the return string will be empty. Be sure to check for this to avoid silent data loss.

Instead of using this function it's also possible to write

std::string s;
wxString wxs;
...
s = std::string(wxs);

but using ToStdString() may make the code more clear.


里面最重要的部分是the current locale   并且会存在fail的情况,转化失败就出现了空字符串,经过进一步确认,我们可以发现问题就出在这里。

我们可以通过 wxLocale来获取 系统的locale,但是我们却无法获取程序运行过程中会话的locale,这是问题之一。

另外我观察到,不调用wxLocale的Init方法和调用了wxLocale的Init方法会产生不同的影响,在我的环境下,在不调用Init方法的时候 程序的locale可能是 en_US(推测),调用了init方法的时候locale变成了 zh_CN,中文可以正常显示,这个可以通过wxLocale验证。

最后我们需要确认一点,locale并不是专为wxString这个变量服务的,他是一个全局性的变量,保存着一些信息用来进行字符转化,这一般使用于本地化操作。locale的改变会影响很多库函数的运行。

在围绕locale进行了一些尝试之后,我得到了如下结论:1处理字符集问题的解决方案不能依赖locale,2修改locale无法解决问题(会导致其他问题,并且部分地方中文还存在无法显示的情况)


探索新解决方案的时候我发现wxT()  可以正确的将中文字符串转化并交给wxString保存,虽然无法通过ToStdString 取出内部值,但是通过size方法可以拿到正确的大小。

接下来就是确认wxT是在做什么

#define wxT (   string )  

This macro can be used with character and string literals (in other words, 'x' or "foo") to automatically convert them to wide strings in Unicode builds of wxWidgets.

This macro simply returns the value passed to it without changes in ASCII build. In fact, its definition is:

1 #ifdef UNICODE
2 # define wxT(x) L##x
3 #else // !Unicode
4 # define wxT(x) x
5 #endif

Note that since wxWidgets 2.9.0 you shouldn't use wxT() anymore in your program sources (it was previously required if you wanted to support Unicode).

See also
Unicode Support in wxWidgets,  wxS()

Include file:

#include  


官方文档中的说法表明wxT实际上是将字符串在wxWidgets支持unicode的情况下转化成宽字符串

那么我们可以确认一点,wstring和wxString 是兼容的,可以正确的进行字符转化。

那么我们可以通过把string转化成wstring 然后传递给wxString,来实现wxString的初始化。

该方法解决了wxString初始化的问题,但是我们怎么从wxString中取出值。


有了wstring到wxString的成功案例,我们很容易就联想到了ToStdWstring方法,官方文档中也是说不存在数据丢失问题,但是很遗憾,经过测试,这个方法还是无效。

在翻阅了wxWidgets支持Unicode 的官方说明文档中 我找到了ToUTF8 这个方法,

const wxScopedCharBuffer wxString::ToUTF8 (   ) const

Same as utf8_str().



const wxScopedCharBuffer wxString::utf8_str (   ) const

Converts the strings contents to UTF-8 and returns it either as a temporary wxCharBuffer object or as a pointer to the internal string contents in UTF-8 build.

See also
wc_str(),  c_str(),  mb_str()

这个方法在 unicode支持  文档中被描述为最可以依赖的无数据丢失的方法,经过验证,可以使用。

wxString转string的途径 : string(wxString.ToUTF8().data())


最后补充上  utf8  string 转化成 utf16的wstring的方法

/*
源自stackoverflow
*/
std::wstring Convert_Util::utf8_to_utf16(const std::string& utf8)
{
    std::vector 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;
}



你可能感兴趣的:(C++)