XMLCh到wchar_t,反之亦然

时间:2014-09-15 01:41:36

标签: c++ wchar-t wstring

我的配置:

  • 编译器:gnu gcc 4.8.2
  • 我用C ++ 11编译
  • platform / OS:Linux 64bit Ubuntu 14.04.1 LTS

我想用wchar_t *提供一个方法,并在需要XMLCh *的许多xecerces库方法中使用它,但我不知道如何从一个方法转换到另一个方法。如果使用char *而不是wchar_t *,这很容易,但我需要使用宽字符。在Windows下,我可以轻松地从一个转换到另一个,但它在我的linux机器上不起作用。不知何故,我必须手动将wchar_t *转换为XMLCh *

我链接到libxerces-c-3.1.so库,它只使用XMLCh *。 XMLCh可以处理广泛的角色,但我不知道如何将它提供给它,以及如何从XMLCh *中获取wchar_t *

我开发了这个,但它不起作用(这里我吐出一个wstring,它比清理指针更容易清理内存:

static inline std::wstring XMLCh2W(const XMLCh* tagname)
{
    std::wstring wstr;
    XMLSize_t len1 = XMLString::stringLen(tagname);
    XMLSize_t outLen = len1 * 4;
    XMLByte ut8[outLen+1];
    XMLSize_t charsEaten = 0;
    XMLTransService::Codes failReason; //Ok | UnsupportedEncoding | InternalFailure | SupportFilesNotFound
    XMLTranscoder* transcoder = XMLPlatformUtils::fgTransService->makeNewTranscoderFor("UTF-8", failReason,16*1024);

    unsigned int utf8Len = transcoder->transcodeTo(tagname,len1,ut8,outLen,charsEaten,XMLTranscoder::UnRep_Throw);// XMLTranscoder::UnRep_Throw UnRep_RepChar

    ut8[utf8Len] = 0;
    std::wstring wstr = std::wstring((wchar_t*)ut8);//I'm not sure this is actually ok to do
    return wstr;
}

3 个答案:

答案 0 :(得分:2)

XMLCh由wchar_t(在Windows上)或uint16_t(在Linux上)定义,并使用UTF-16进行编码。

不幸的是,gcc 4.8.2不支持std :: wstring_convert来转换unicode字符串的编码。但是您可以使用Boost的locale :: conv :: utf_to_utf()来转换为/来自XMLCh。

#include <boost/locale.hpp>

static inline std::wstring XMLCh2W(const XMLCh* xmlchstr)
{
    std::wstring wstr = boost::locale::conv::utf_to_utf<wchar_t>(xmlchstr);
    return wstr;
}

static inline std::basic_string<XMLCh> W2XMLCh(const std::wstring& wstr)
{
    std::basic_string<XMLCh> xmlstr = boost::locale::conv::utf_to_utf<XMLCh>(wstr);
    return xmlstr;
}

如果你想使用wchar_t *或XMLCh *,请使用如下所示的c_str()方法。

const wchar_t* wcharPointer = wstr.c_str();
const XMLCh* xmlchPointer = xmlstr.c_str();

答案 1 :(得分:1)

不,你不能在GCC下这样做,因为GCC将wchar_t定义为32位,UTF-32 / UCS-4编码(差异对于实际用途并不重要)字符串而Xerces-c将XmlCh定义为16位UTF-16编码的字符串。

我发现最好的是使用C ++ 11支持UTF-16字符串:

  • char16_tXmlCh是等效的,但不能隐含地兑换;你还需要在他们之间施放。但与转码相比,这至少是便宜的。
  • std::basic_string<char16_t>是等效的字符串类型。
  • 使用u"str"u's'形式的文字。

不幸的是,VC ++并不支持C ++ 11 UTF-16文字,尽管wchar_t文字是UTF-16编码的。所以我最终在标题中得到了类似的东西:

#if defined _MSC_VER
#define U16S(x) L##x
typedef wchar_t my_u16_char_t;
typedef std::wstring my_u16_string_t;
typedef std::wstringstream my_u16_sstream_t;
inline XmlCh* XmlString(my_u16_char_t* s) { return s; }
inline XmlCh* XmlString(my_u16_string_t* s) { return s.c_str(); }
#elif defined __linux
#define U16S(x) u##x
typedef char16_t my_u16_char_t;
typedef std::basic_string<my_u16_char_t> my_u16_string_t;
typedef std::basic_stringstream<my_u16_char_t> my_u16_sstream_t;
inline XmlCh* XmlString(my_u16_char_t* s) { return reinterpret_cast<XmlCh*>(s); }
inline XmlCh* XmlString(my_u16_string_t* s) { return XmlString(s.c_str()); }
#endif

IMO,相当混乱,但在VC ++支持C ++ 11 Unicode文字之前,我看不到整理,允许Xerces直接用char16_t重写。

答案 2 :(得分:1)

我最近处理过这个问题,现在Visual Studio 2015支持Unicode字符和字符串文字,这很容易以跨平台的方式处理。我使用以下宏和static_assert来保证正确性:

#define CONST_XMLCH(s) reinterpret_cast<const ::XMLCh*>(u ## s)

static_assert(sizeof(::XMLCh) == sizeof(char16_t), 
    "XMLCh is not sized correctly for UTF-16.");

使用示例:

const XMLCh* features = CONST_XMLCH("Core");
auto impl = DOMImplementationRegistry::getDOMImplementation(features);

这是因为Xerces将XMLCh定义为16位宽并保存UTF-16字符串值,这完全符合标准给出的前缀为u的字符串文字的定义。编译器不知道这一点,并且不会在char16_t*XMLCh*之间进行隐式转换,但是你可以使用reinterpret_cast来解决这个问题。如果出于某种原因你尝试在大小不匹配的平台上编译Xerces,static_assert将失败并引起对问题的注意。