如何将一个区域设置的std::string
转换为另一个区域设置?
例如,我在std::string
中有std::locale("ru_RU.koi8r")
以及在std::string
或std::locale("ru_RU.CP1251")
或其他任何内容中创建std::locale("zh_CN.gb18030")
的内容。
答案 0 :(得分:0)
是的,codecvt
是解决此类问题的正确答案。
codecvt<internal, external, state>
方面的目标是提供内部表示(内存中的变量)和流表示(文件中的数据)之间的流字符编码转换:
imbue()
定义。do_in()
进行内部编码。 do_out()
从内部数据到外部(存储在文件中)进行转换。 我在文件中的代码页850格式和内存中的iso8859-1之间进行转换的非常简单的示例。当然,你可以调整它来为koi8r和CP1251做同样的事情。
原则如下:
由于我的示例中的字符集都是针对类型char
定义的,因此我创建了自己的字符集,如下所示:
class codecvt_cp850_iso8859 : public codecvt < char, char, mbstate_t > {
public:
explicit codecvt_cp850_iso8859(size_t r=0) : codecvt(r) {}
protected:
result do_in(mbstate_t &s, const char *from, const char *from_end,
const char*&from_next,
char *to, char*to_end, char*&to_next) const // from cp850 to iso8859-1
{
result res=partial;
const char*p;
for (p = from; p != from_end && to != to_end; p++)
*to++ = ... /* your stuff here, for example a conversion table */
from_next = p; // what's the next char to convert
to_next = to; // what's the next place to convert to
if (p == from_end)
res = p == from ? noconv : ok;
return res;
}
result do_out(mbstate_t &s, const char *from, const char *from_end, const char*&from_next,
char *to, char*to_end, char*&to_next) const // from iso8859-1 to cp850
{
result res = partial;
const char*p;
for (p = from; p != from_end && to != to_end; p++)
*to++ = ... /* conversion in the other direction */
from_next = p; to_next = to;
if (p == from_end)
res = p == from ? noconv : ok;
return res;
}
result do_unshift(mbstate_t &s, char*to, char*to_end, char*& to_next) const {
to_next = to; // Attention MSVC segfaults if this is missing !
return ok;
}
int encoding() const { return 1; } // fixed length for external representation
bool do_always_noconv() const { return false; }
然后您可以使用此类代码:
// read with conversion from cp850 in stream to iso in memory
ifstream is850("test-cp850.txt");
is850.imbue(locale(is850.getloc(), new codecvt_cp850_iso8859 ())); // use our conversion
getline(is850, isotext);
...
// writing an iso string to a CP850 file:
ofstream os850("test-cp850fromiso.txt");
os850.imbue(locale(os850.getloc(), new codecvt_cp850_iso8859()));
os850 << myisotext << endl;
...
请注意,标准库对提供的codect拥有所有权,并在不再需要时将其重新关联。
最后,您还可以使用codecvt在内存中的两种格式之间转换字符串。
如下面的评论所示,字符串本身没有区域设置。
所以一种方法是使用stringstreams。另一种方法是直接使用codecvt's functions(mycodecvt::in()
,mycodecvt::out()
和mycodecvt::length()
)
最后一种方法是使用wstring_convert
。但是这个具有要求具有宽字符的转换的不便之处。