Как переносить запись std :: wstring в файл? - PullRequest
18 голосов
/ 29 октября 2010

У меня есть wstring, объявленный как таковой:

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

Литерал будет в кодировке UTF-8, потому что мой исходный файл.

[РЕДАКТИРОВАТЬ: Согласно Марк Рэнсом это не обязательно так, компилятор решит, какую кодировку использовать - вместо этого давайте предположим, что я читаю эту строку из файла, закодированного, например, в. UTF-8]

Я бы очень хотел получить это для чтения файла (когда текстовый редактор настроен на правильную кодировку)

abcàdëefŸg€hhhhhhhµa

, но ofstream не очень совместим (отказывается принимать параметры wstring), и wofstream предположительно должен знать настройки локали и кодировки. Я просто хочу вывести этот набор байтов. Как обычно это делают?

EDIT: он должен быть кроссплатформенным, и не должен полагаться на кодировку UTF-8 . У меня просто есть набор байтов, хранящихся в wstring, и я хочу вывести их. Это вполне может быть UTF-16 или обычный ASCII.

Ответы [ 9 ]

30 голосов
/ 14 августа 2013

Для std::wstring вам нужно std::wofstream

std::wofstream f(L"C:\\some file.txt");
f << str;
f.close();
14 голосов
/ 29 октября 2010

std::wstring для чего-то вроде UTF-16 или UTF-32, не UTF-8. Для UTF-8 вы, вероятно, просто хотите использовать std::string и писать через std::cout. Просто FWIW, C ++ 0x будет иметь литералы Unicode, которые должны помочь прояснить подобные ситуации

7 голосов
/ 29 октября 2010

Почему бы не записать файл в двоичном виде.Просто используйте ofstream с параметром std :: ios :: binary.Редактор должен быть в состоянии интерпретировать это тогда.Не забудьте флаг Unicode 0xFEFF в начале.Возможно, вам лучше написать с библиотекой, попробуйте один из них:

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

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

http://utfcpp.sourceforge.net/

4 голосов
/ 29 октября 2010

C ++ имеет средства для выполнения преобразования широких символов в локализованные при выводе или записи в файл. Используйте для этой цели фасет codecvt.

Вы можете использовать стандартную std :: codecvt_byname или нестандартную реализацию codecvt_facet .

#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 может отправлять преобразования только для локалей, установленных в системе. Поэтому я рекомендую искать в стеке поток "utf8 codecvt" "и сделайте выбор из множества приведенных ссылок на собственные реализации codecvt.

EDIT: Поскольку OP заявляет, что строка уже закодирована, все, что он должен сделать, это удалить префиксы L и "w" из каждого токена своего кода.

2 голосов
/ 29 октября 2010

Существует (специфичное для 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;
}
0 голосов
/ 29 октября 2010

Из моего опыта работы с различными кодировками символов я бы порекомендовал вам иметь дело только с UTF-8 при загрузке и сэкономить время. Вам будет очень больно, если вы попытаетесь сохранить внутреннее представление в UTF-8, поскольку один символ может быть любым от 1 байта до 4. Поэтому простые операции, такие как strlen, требуют, чтобы каждый байт решал, а не len выделенный буфер (хотя вы можете оптимизировать, посмотрев на первый байт в последовательности символов, например, 00..7f - это однобайтовый символ, c2..df указывает на 2-байтовый символ и т. д.).

Люди часто ссылаются на «строки Unicode», когда они имеют в виду UTF-16, а в Windows wchar_t имеет фиксированные 2 байта. В Windows я думаю, что wchar_t это просто:

typedef SHORT wchar_t;

Полное 4-байтовое представление UTF-32 редко требуется и очень расточительно, вот что говорит по этому поводу стандарт Unicode (5.0):

"В среднем более 99% всех UTF-16 выражается в единичных единицах кода ... UTF-16 обеспечивает правильное сочетание компактных размеров с возможностью обработки случайных символов вне BMP"

Короче говоря, используйте whcar_t в качестве внутреннего представления и выполняйте преобразования при загрузке и сохранении (и не беспокойтесь о полном Unicode, если вы не уверены, что он вам нужен).

Что касается выполнения фактического преобразования, взгляните на проект ICU:

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

0 голосов
/ 29 октября 2010

Вы должны , а не использовать исходный файл в кодировке UTF-8, если вы хотите написать переносимый код.Извините.

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

(Я не уверен, действительно ли это вредит стандарту, но я думаю, что это так. Но даже если, чтобы быть в безопасности, вы не должны.)использование std::ostream не будет работать.Есть много способов конвертировать wstring в UTF-8.Мой любимый использует Международные компоненты для Unicode .Это большая библиотека, но это здорово.Вы получите много дополнений и вещей, которые могут вам понадобиться в будущем.

0 голосов
/ 29 октября 2010

У меня была такая же проблема некоторое время назад, и я записал решение, которое нашел в своем блоге. Возможно, вы захотите проверить, не поможет ли это, особенно функция wstring_to_utf8.

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

0 голосов
/ 29 октября 2010

Обратите внимание, что широкие потоки выводят только переменные char *, поэтому, возможно, вам следует попробовать использовать функцию-член c_str() для преобразования std::wstring и затем вывести его в файл. Тогда это, вероятно, должно работать?

...