LINUX.ORG.RU

Локали, кодировки

 


1

1

Привет. У меня просто каша в голове на эту тему. Из справочника:

All file I/O operations performed through std::basic_fstream<CharT> use the std::codecvt<CharT, char, std::mbstate_t> facet of the locale imbued in the stream. 

std::codecvt<char, char, std::mbstate_t> 	identity conversion
std::codecvt<char16_t, char8_t, std::mbstate_t> 	conversion between UTF-16 and UTF-8 (since C++20)
std::codecvt<char32_t, char8_t, std::mbstate_t> 	conversion between UTF-32 and UTF-8 (since C++20)
std::codecvt<wchar_t, char, std::mbstate_t> 	conversion between the system's native wide and the single-byte narrow character sets 

Из прочитанного создаётся ощущение, что все специализации fstream (кроме wchar_t и char) должны конвертировать в utf-8, а wchar_t в narrow char.

Что показывает практика: C utf-32 вроде так и происходит - на выходе в файле utf-8. А вот поведение wchar_t вообще не сходится с документацией. Он конвертирует не в narrow char, а в кодировку локали:

    basic_ofstream<wchar_t> f("22");
    locale l(f.getloc(), new std::codecvt_byname<wchar_t, char, mbstate_t>("ru_RU.CP1251"));
    f.imbue(l);
    f << L"й";

на выходе кс1251. Если локаль не указывать, то записи вообще нет. Пусть так, может даже удобно, но я вообще не увидел описание такого поведения в доках. Может это гцц специфично и вообще нестандартно? И кросплатформенно использовать wfstream для перекодировок не стоит. Ещё интересно можно ли во время выполнения узнать доступные локали (стд способами)? я не нашёл.

All in all, I believe this proves that software developers as a whole and as a culture produce worse results than drug addicted butt fucked monkeys randomly hacking on typewriters while inhaling the fumes of a radioactive dumpster fire fueled by chinese platsic toys for children and Elton John/Justin Bieber crossover CDs for all eternity.

olelookoe ()

Он конвертирует не в narrow char, а в кодировку локали

А что такое narrow char, если не мультибайтовая кодировка локали?

Если локаль не указывать, то записи вообще нет.

Если её не указывать, то используется локаль по умолчанию, которая «C», если её не установить (std::setlocale(LC_ALL, ""); чтобы взять системную), а в «C» й нету.

Ещё интересно можно ли во время выполнения узнать доступные локали (стд способами)?

Вроде, нет такого.

xaizek ★★★★★ ()
Ответ на: комментарий от xaizek

А что такое narrow char, если не мультибайтовая кодировка локали?

Ну кодировка локали, это кодировка локали, может быть любой, а narrow charcter string - это «текс без префикса в исходнике».

Если её не указывать, то используется локаль по умолчанию, которая «C», если её не установить (std::setlocale(LC_ALL, ""); чтобы взять системную), а в «C» й нету.

Да, наверное так и есть, но это все равно не поведение из доков.

Вообще начинаю приходить к мнениею, что есть две кодировки - ютф8 и ютф32(ну если надо в софтине посимвольно работать со строкой, конвертируем в ран тайме в него). Стандартный codcvt умеет конвертацию между ними. Если кто-то не может/не умеет ютф8 (шрифт/консоль), какая-нибудь там вин консоль не хочет подстроиться под «нормальный» текст, то это её проблемы, пусть горит вместе со всем остальным вагоном кодировок.

pavlick ()
Последнее исправление: pavlick (всего исправлений: 1)
Ответ на: комментарий от pavlick

narrow charcter string - это «текс без префикса в исходнике».

То в контексте разбора исходника может быть, а вообще (basic.fundamental):

The three types char, signed char, and unsigned char are collectively called ordinary character types.
The ordinary character types and char8_­t are collectively called narrow character types.

locale.codecvt:

codecvt<wchar_­t, char, mbstate_­t> converts between the native character sets for ordinary and wide characters.

Да, наверное так и есть, но это все равно не поведение из доков.

locale.facet:

For some standard facets a standard “…_­byname” class, derived from it, implements the virtual function semantics equivalent to that facet of the locale constructed by locale(const char*) with the same name.

locale.cons:

explicit locale(const char* std_name);
Effects: Constructs a locale using standard C locale names, e.g., "POSIX".
The resulting locale implements semantics defined to be associated with that name.

Хотя не уверен, что пустая строка в качестве имени локали в стандарте оговорена. Может это подразумевается под «standard C locale names».

xaizek ★★★★★ ()
Последнее исправление: xaizek (всего исправлений: 2)
Ответ на: комментарий от xaizek

codecvt<wchar_­t, char, mbstate_­t> converts between the native character sets for ordinary and wide characters.

Здесь звучит иначе, это хорошо. Но всё же на пути к использованиею wchar_t - проблемы, как кодировать в него/из него? Да ещё и кроссплатформенно и стд. Заканчивая тем, что хз как узнать установленные в системе локали.

ЗЫ: спасибо за цитаты.

pavlick ()
Последнее исправление: pavlick (всего исправлений: 2)
Ответ на: комментарий от pavlick

Для преобразований всегда есть сишные:

codecvt их как бы и использует, что видно по mbstate_t.

xaizek ★★★★★ ()

Кстати, если кто будет менять кодировку выхлопа от wcout, то отвяжитесь от stdio sync_with_stdio(false).

#include <locale>
#include <iostream>
using namespace std;
int main()
{
    locale l(wcout.getloc(), new codecvt_byname<wchar_t, char, mbstate_t>("ru_RU.CP1251"));
    wcout.sync_with_stdio(false);
    wcout.imbue(l);
    wcout << L"йц";
}
pavlick ()