22

我有一个wstring这样的声明:

// random wstring
std::wstring str = L"abcàdëefŸg€hhhhhhhµa";

文字将是 UTF-8 编码的,因为我的源文件是。

[编辑:根据 Mark Ransom 的说法,情况不一定如此,编译器将决定使用什么编码 - 让我们假设我从一个以 UTF-8 编码的文件中读取这个字符串]

我非常想把它读入文件读取(当文本编辑器设置为正确的编码时)

abcàdëefŸg€hhhhhhhµa

ofstream不是很合作(拒绝接受wstring参数),wofstream据说需要知道语言环境和编码设置。我只想输出这组字节。通常如何做到这一点?

编辑:它必须是跨平台的,并且不应依赖于 UTF-8 的编码。我只是碰巧有一组字节存储在 a 中wstring,并且想要输出它们。它很可能是 UTF-16 或纯 ASCII。

4

9 回答 9

43

因为std::wstring你需要std::wofstream

std::wofstream f(L"C:\\some file.txt");
f << str;
f.close();
于 2013-08-14T08:11:13.663 回答
15

std::wstring适用于 UTF-16 或 UTF-32,而不是UTF-8。对于 UTF-8,您可能只想使用std::string,并通过std::cout. 只是 FWIW,C++0x 将有 Unicode 文字,这应该有助于澄清这种情况。

于 2010-10-29T16:39:05.787 回答
8

为什么不将文件写为二进制文件。只需将 ofstream 与 std::ios::binary 设置一起使用。那时编辑应该能够解释它。不要忘记开头的 Unicode 标志 0xFEFF。您可能会更好地使用库编写,请尝试以下其中一种:

http://www.codeproject.com/KB/files/EZUTF.aspx

http://www.gnu.org/software/libiconv/

http://utfcpp.sourceforge.net/

于 2010-10-29T16:57:19.433 回答
5

这里有一个(特定于 Windows 的)解决方案应该适合您。基本上,转换wstring为 UTF-8 代码页,然后使用ofstream.

#include < windows.h >

std::string to_utf8(const wchar_t* buffer, int len)
{
        int nChars = ::WideCharToMultiByte(
                CP_UTF8,
                0,
                buffer,
                len,
                NULL,
                0,
                NULL,
                NULL);
        if (nChars == 0) return "";

        string newbuffer;
        newbuffer.resize(nChars) ;
        ::WideCharToMultiByte(
                CP_UTF8,
                0,
                buffer,
                len,
                const_cast< char* >(newbuffer.c_str()),
                nChars,
                NULL,
                NULL); 

        return newbuffer;
}

std::string to_utf8(const std::wstring& str)
{
        return to_utf8(str.c_str(), (int)str.size());
}

int main()
{
        std::ofstream testFile;

        testFile.open("demo.xml", std::ios::out | std::ios::binary); 

        std::wstring text =
                L"< ?xml version=\"1.0\" encoding=\"UTF-8\"? >\n"
                L"< root description=\"this is a naïve example\" >\n< /root >";

        std::string outtext = to_utf8(text);

        testFile << outtext;

        testFile.close();

        return 0;
}
于 2010-10-29T16:39:44.243 回答
5

C++ 有办法在输出或文件写入时执行从宽字符到本地化字符的转换。为此目的使用codecvt 方面。

您可以使用标准std::codecvt_byname或非标准 codecvt_facet implementation

#include <locale>
using namespace std;
typedef codecvt_facet<wchar_t, char, mbstate_t> Cvt;
locale utf8locale(locale(), new codecvt_byname<wchar_t, char, mbstate_t> ("en_US.UTF-8"));
wcout.imbue(utf8locale);
wcout << L"Hello, wide to multybyte world!" << endl;

请注意,在某些平台上,codecvt_byname 只能为系统中安装的语言环境发出转换。因此,我建议在 stackoverflow 中搜索“utf8 codecvt”,并从列出的许多自定义 codecvt 实现的参考中进行选择。

编辑:由于 OP 声明字符串已经编码,他应该做的就是从他的代码的每个标记中删除前缀 L 和“w”。

于 2010-10-29T17:03:49.793 回答
0

I had the same problem some time ago, and wrote down the solution I found on my blog. You might want to check it out to see if it might help, especially the function wstring_to_utf8.

http://pileborg.org/b2e/blog5.php/2010/06/13/unicode-utf-8-and-wchar_t

于 2010-10-29T17:08:09.017 回答
0

如果要编写可移植代码,则不应使用 UTF-8 编码的源文件。对不起。

  std::wstring str = L"abcàdëefŸg€hhhhhhhµa";

(我不确定这是否真的会损害标准,但我认为确实如此。但即使,为了安全起见,你也不应该这样做。)

是的,纯粹使用是std::ostream行不通的。有很多方法可以将 a 转换wstring为 UTF-8。我最喜欢的是使用International Components for Unicode。这是一个很大的库,但它很棒。你会得到很多额外的东西和将来可能需要的东西。

于 2010-10-29T17:41:08.137 回答
0

根据我使用不同字符编码的经验,我建议您仅在加载时处理 UTF-8 并节省时间。如果您尝试将内部表示存储在 UTF-8 中,您将陷入痛苦的世界,因为单个字符可能是 1 字节到 4 之间的任何字符。所以像 strlen 这样的简单操作需要查看每个字节来决定 len 而不是分配的缓冲区(尽管您可以通过查看 char 序列中的第一个字节来优化,例如 00..7f 是单字节字符,c2..df 表示 2 字节字符等)。

当他们表示 UTF-16 时,人们经常提到“Unicode 字符串”,而在 Windows 上 wchar_t 是固定的 2 个字节。在 Windows 中,我认为 wchar_t 很简单:

typedef SHORT wchar_t;

很少需要完整的 UTF-32 4 字节表示并且非常浪费,这里是 Unicode 标准 (5.0) 必须说的:

“平均而言,超过 99% 的 UTF-16 是使用单个代码单元表示的……UTF-16 提供了紧凑的大小与处理 BMP 之外的偶尔字符的能力的正确组合”

简而言之,使用 whcar_t 作为您的内部表示并在加载和保存时进行转换(除非您知道需要它,否则不要担心完整的 Unicode)。

关于执行实际转换,请查看 ICU 项目:

http://site.icu-project.org/

于 2010-10-29T17:48:17.933 回答
0

请注意,宽流仅输出 char * 变量,因此您应该尝试使用c_str()成员函数转换 astd::wstring然后将其输出到文件中。那么它应该可以工作吗?

于 2010-10-29T16:43:16.547 回答