我的配置:
我想用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;
}
答案 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_t
和XmlCh
是等效的,但不能隐含地兑换;你还需要在他们之间施放。但与转码相比,这至少是便宜的。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
将失败并引起对问题的注意。