" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文档下蝲>
locale和facet
C++的locale框架比C更完备。C++除了一个笼l本地策略集localeQ还可以为locale指定具体的策略facetQ甚臛_以用自己定义的facetL造一个现有的locale产生一个新的locale。如果有一个facetcNewFacet需要添加到某个old_loc中Ş成新new_locQ需要另外一个构造函敎ͼ通常的做法是Q?br>std::locale new_loc(old_loc, new NewFacet);
标准库里的标准facet都具有自q有的功能Q访问一个locale对象中特定的facet需要用模板函数use_facetQ?br>template <class Facet> const Facet& use_factet(const locale&);
换一U说法,use_facet把一个facetcd例化成了对象Q由此就可以使用q个facet对象的成员函数?br>
codecvt
codecvt是一个标准facet。在C++的设计框枉Q这是一个通用的代码{换模李쀔—也是_q不是仅仅ؓ(f)宽窄转换制定的?br>templat <class I, class E, class State> class std::codecvt: public locale, public codecvt_base{...};
I表示内部~码QE表示外部~码QState是不同{换方式的标识Q如果定义如下类型:(x)
typedef std::codecvt<wchar_t, char, mbstate_t> CodecvtFacet;
那么CodecvtFacet是一个标准的宽窄转换facetQ其中mbstate_t是标准宽H{换的State?br>
内部~码和外部编?br>
我们考虑W?节中提到的C++~译器读取源文g时候的情ŞQ当dL"中文abc"的时候,外部~码Q也是源文件的~码Q是GB2312或者UTF-8的charQ而编译器必须其译为UCS-2BE或者UTF-32BE的wchar_tQ这也就是程序的内部~码。如果不是宽字符Ԍ内外~码都是charQ也׃需要{换了。类似的Q当C++d文g的时?Q就?x)可能需要到内外~码转换。事实上Qcodecvt正是被文g缓存basic_filebuf所使用的。理解这一点很重要Q原因会(x)在下一节看到?br>
CodecvtFacet的in()和out()
因ؓ(f)在CodecvtFacet中,内部~码讄为wchar_tQ外部编码设|ؓ(f)charQ{换模式是标准宽窄转换mbstate_tQ所以,cL法in()是从char标准转换到wchar_tQout()是从wchar_t标准转换到char。这成了我们正需要的内外转换函数?br>result in(State& s, const E* from, const E* from_end, const E*& from_next, I* to, I* to_end, I*& to_next) const;
result out(State& s, const I* from, const I* from_end, const I*& from_next, E* to, E* to_end, E*& to_next) const;
其中Qs是非const引用Q保存着转换位移状态信息。这里需要重点强调的是,因ؓ(f)转换的实际工作交l了q行时库Q也是_转换可能不是在程序的主进E中完成的,而{换工作依赖于查询s的|因此Q如果s在{换结束前析构Q就可能抛出q行时异常。所以,最安全的办法是Q将s讄为全局变量Q?br>const?个指针分别是待{换字W串的v点,l点Q和出现错误时候的停点Q的下一个位|)Q另?个指针是转换目标字符串的L(fng)Q终点以及出现错误时候的停点Q的下一个位|)?br>
代码如下Q?br>头文?br>
//Filename string_wstring_cppcvt.hpp
#ifndef STRING_WSTRING_CPPCVT_HPP
#define STRING_WSTRING_CPPCVT_HPP
#include <iostream>
#include <string>
const std::wstring s2ws(const std::string& s);
const std::string ws2s(const std::wstring& s);
#endif
实现Q?br>
#include "string_wstring_cppcvt.hpp"
mbstate_t in_cvt_state;
mbstate_t out_cvt_state;
const std::wstring s2ws(const std::string& s)
{
std::locale sys_loc("");
const char* src_str = s.c_str();
const size_t BUFFER_SIZE = s.size() + 1;
wchar_t* intern_buffer = new wchar_t[BUFFER_SIZE];
wmemset(intern_buffer, 0, BUFFER_SIZE);
const char* extern_from = src_str;
const char* extern_from_end = extern_from + s.size();
const char* extern_from_next = 0;
wchar_t* intern_to = intern_buffer;
wchar_t* intern_to_end = intern_to + BUFFER_SIZE;
wchar_t* intern_to_next = 0;
typedef std::codecvt<wchar_t, char, mbstate_t> CodecvtFacet;
CodecvtFacet::result cvt_rst =
std::use_facet<CodecvtFacet>(sys_loc).in(
in_cvt_state,
extern_from, extern_from_end, extern_from_next,
intern_to, intern_to_end, intern_to_next);
if (cvt_rst != CodecvtFacet::ok) {
switch(cvt_rst) {
case CodecvtFacet::partial:
std::cerr << "partial";
break;
case CodecvtFacet::error:
std::cerr << "error";
break;
case CodecvtFacet::noconv:
std::cerr << "noconv";
break;
default:
std::cerr << "unknown";
}
std::cerr << ", please check in_cvt_state."
<< std::endl;
}
std::wstring result = intern_buffer;
delete []intern_buffer;
return result;
}
const std::string ws2s(const std::wstring& ws)
{
std::locale sys_loc("");
const wchar_t* src_wstr = ws.c_str();
const size_t MAX_UNICODE_BYTES = 4;
const size_t BUFFER_SIZE =
ws.size() * MAX_UNICODE_BYTES + 1;
char* extern_buffer = new char[BUFFER_SIZE];
memset(extern_buffer, 0, BUFFER_SIZE);
const wchar_t* intern_from = src_wstr;
const wchar_t* intern_from_end = intern_from + ws.size();
const wchar_t* intern_from_next = 0;
char* extern_to = extern_buffer;
char* extern_to_end = extern_to + BUFFER_SIZE;
char* extern_to_next = 0;
typedef std::codecvt<wchar_t, char, mbstate_t> CodecvtFacet;
CodecvtFacet::result cvt_rst =
std::use_facet<CodecvtFacet>(sys_loc).out(
out_cvt_state,
intern_from, intern_from_end, intern_from_next,
extern_to, extern_to_end, extern_to_next);
if (cvt_rst != CodecvtFacet::ok) {
switch(cvt_rst) {
case CodecvtFacet::partial:
std::cerr << "partial";
break;
case CodecvtFacet::error:
std::cerr << "error";
break;
case CodecvtFacet::noconv:
std::cerr << "noconv";
break;
default:
std::cerr << "unknown";
}
std::cerr << ", please check out_cvt_state."
<< std::endl;
}
std::string result = extern_buffer;
delete []extern_buffer;
return result;
}
最后补充说明一下std::use_facet<CodecvtFacet>(sys_loc).in()和std::use_facet<CodecvtFacet>(sys_loc).out()。sys_loc是系l的localeQ这个locale中就包含着特定的codecvt facetQ我们已ltypedefZCodecvtFacet。用use_facet对CodecvtFacetq行了实例化Q所以可以用这个facet的方法in()和out()?

]]>