тысяча третий раз про Юникод
От: pepsicoca  
Дата: 14.10.09 08:18
Оценка:
Добрый день.

Итак, подведу итоги обсуждения и экспериментов.

Есть MSVC2003 и есть программа:

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{

std::wcout<<L"hello"<<std::endl;
std::wcout<<L"привет"<<std::endl;

return 0;
}


Она НЕ печатает кириллицу.

Есть другая программа, в которой добавлен вызов std::wcout.imbue(std::locale("rus_rus.866"));:

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{

std::wcout.imbue(std::locale("rus_rus.866"));

std::wcout<<L"hello"<<std::endl;
std::wcout<<L"привет"<<std::endl;

return 0;
}


Она ПЕЧАТАЕТ кириллицу.

Выяснилось, что в исходнике кирилическая строка L"привет" хранится в виде кода 1251 (0xef 0xf0 0xe8 0xe2 0xe5 0xf2).
Выяснилось, что в экзешнике кирилическая строка L"привет" хранится в виде Юникода (двухбайтовые символы 0x043f,0x0440,0x0438,0x0432,0x0435,0x0442)

Выяснилось, что директивы

#pragma setlocale( "rus_rus.866" )
#pragma setlocale( "russian" )

не помогают напечатать кириллицу. Кириллица начинает печататься только после
вызова std::wcout.imbue(std::locale("rus_rus.866"));

В связи с этим вопросы:

1. Транслятор формирует Юникодную строку "привет" из ASCIIшной строки "привет". Как транслятор понимает, что символы в исходнике из второй половины таблицы это кириллица? А не, например, греческие буквы. То есть откуда транслятор берет локаль при компиляции?

2. Если в исходнике будет несколько сообщений "привет" на разных языках, то как транслятор сформирует Юникод для каждого из них? Откуда он узнает локаль текущего сообщения?

3. Если в экзешнике уже лежит Юникодная строка, почему кириллица не печатается без явного указания локали функцией imbue? Ведь по Юникоду однозначно определяется начертание символа. И чтобы напечатать Юникод локаль не нужна.

Спасибо.
Re: тысяча третий раз про Юникод
От: jazzer Россия Skype: enerjazzer
Дата: 14.10.09 08:38
Оценка:
Здравствуйте, pepsicoca, Вы писали:

P>Она НЕ печатает кириллицу.

P>Есть другая программа, в которой добавлен вызов std::wcout.imbue(std::locale("rus_rus.866"));:

В качестве дикого предположения (я под винду не программирую)...
Ты ведь, наверное, имеешь в виду, что не печатает в терминале? Так он не юникодный, скорее всего.
Попробуй распечатать в файл, а не на экран консоли, а потом открыть его Блокнотом — в файле будет юникодная русская строка или нет?
Если мое предположение верно, то это беда виндовой консоли.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: тысяча третий раз про Юникод
От: pepsicoca  
Дата: 14.10.09 09:51
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, pepsicoca, Вы писали:


P>>Она НЕ печатает кириллицу.

P>>Есть другая программа, в которой добавлен вызов std::wcout.imbue(std::locale("rus_rus.866"));:

J>В качестве дикого предположения (я под винду не программирую)...

J>Ты ведь, наверное, имеешь в виду, что не печатает в терминале? Так он не юникодный, скорее всего.

Зная, что терминал не юникодный и зная, что нужно выводить кириллицу (это можно узнать из Юникодного кода кирилических символов) почему бы системе самой перед выводом кирилицы не сделать imbue той локали, которая нужна?

J>Попробуй распечатать в файл, а не на экран консоли, а потом открыть его Блокнотом — в файле будет юникодная русская строка или нет?

J>Если мое предположение верно, то это беда виндовой консоли.

Вот пример с файлом:

#include "stdafx.h"
#include <fstream>

int _tmain(int argc, _TCHAR* argv[])
{

std::wofstream o1("example.txt");

o1<<L"hello"<<std::endl;
o1<<L"привет"<<std::endl;

return 0;
}


Этот пример печатает в файл только латинское hello. Причем не в Юникоде, а в ASCII.
Re: тысяча третий раз про Юникод
От: K13 http://akvis.com
Дата: 14.10.09 10:37
Оценка: +1
P>Выяснилось, что в исходнике кирилическая строка L"привет" хранится в виде кода 1251 (0xef 0xf0 0xe8 0xe2 0xe5 0xf2).

it depends. Вот у нас за такой исходник можно получить по башке, потому что принято решение все исходники сохранять как UTF-8 без BOM.
Иначе возникают проблемы на маке
По умолчанию студия сохраняет в системной локали, но это можно изменять (File / Advanced Save Options).
Есть небольшая засада -- пока нет хотя бы одного не-ASCII символа, при загрузке она сбрасывает настройку на текущую локаль.
Но тем не менее.... кодировка исходника особого значения не имеет.

P>Выяснилось, что в экзешнике кирилическая строка L"привет" хранится в виде Юникода (двухбайтовые символы 0x043f,0x0440,0x0438,0x0432,0x0435,0x0442)


собственно, конструкция L"" для этого и придумана. только число байтиков зависит от размера wchar_t.


P>3. Если в экзешнике уже лежит Юникодная строка, почему кириллица не печатается без явного указания локали функцией imbue? Ведь по Юникоду однозначно определяется начертание символа. И чтобы напечатать Юникод локаль не нужна.


потоки ввода-вывода работают с char. Без указания, какая именно кодировка является активной, не обойтись.
"Переключать на ходу" нельзя -- иначе при пайпе/записи в файл нам надо вставлять мета-символы между символами сообщения, а делать это мы не вправе.
Re[2]: тысяча третий раз про Юникод
От: Sergey Россия  
Дата: 14.10.09 10:45
Оценка:
Здравствуйте, jazzer, Вы писали:

P>>Она НЕ печатает кириллицу.

P>>Есть другая программа, в которой добавлен вызов std::wcout.imbue(std::locale("rus_rus.866"));:

J>В качестве дикого предположения (я под винду не программирую)...

J>Ты ведь, наверное, имеешь в виду, что не печатает в терминале? Так он не юникодный, скорее всего.
J>Попробуй распечатать в файл, а не на экран консоли, а потом открыть его Блокнотом — в файле будет юникодная русская строка или нет?
J>Если мое предположение верно, то это беда виндовой консоли.

Заметно, что под винду не программируешь. С файлами в VC вообще жесткий прикол — они по умолчанию из широких строк в узкие конвертируют.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: тысяча третий раз про Юникод
От: andrey.desman  
Дата: 14.10.09 10:51
Оценка: +1
Здравствуйте, pepsicoca, Вы писали:

P>1. Транслятор формирует Юникодную строку "привет" из ASCIIшной строки "привет". Как транслятор понимает, что символы в исходнике из второй половины таблицы это кириллица? А не, например, греческие буквы. То есть откуда транслятор берет локаль при компиляции?


Потому что это твоя системная локаль. Открой "Панель Управления -> Язык и региональные стандарты -> Язык программ, не поддерживающих юникод" и поменяй на другой. В экзешнике будет уже что-то другое.

P>2. Если в исходнике будет несколько сообщений "привет" на разных языках, то как транслятор сформирует Юникод для каждого из них? Откуда он узнает локаль текущего сообщения?


В исходнике не может быть нескольких сообщений на разных языках, потому что ты ограничен таблицей cp1251. Если конечно сам исходник не в юникоде записан. Правда я не знаю, поддерживает ли студия компиляцию юникодных исходников.

P>3. Если в экзешнике уже лежит Юникодная строка, почему кириллица не печатается без явного указания локали функцией imbue? Ведь по Юникоду однозначно определяется начертание символа. И чтобы напечатать Юникод локаль не нужна.


Тут я возможно не прав, но.... Есть кодовая страница, с которой работает консоль. Есть кодовая страница, которая используется std::wcout для перевода Юникода в однобайтные символы. Так вот, консоль по дефолту принимает символы в oem866. Виндовая локаль по дефолту стоит в cp1251, именно ее использует std::wcout для преобразования юникода в однобайтные символы перед тем, как скормить текст win32 console api. Так и получается, что std::wcout переводит юникод в cp1251 и спихивает результат консоли, которая ожидает oem866, отсюда и кракозябры.
Re[3]: тысяча третий раз про Юникод
От: Rakafon Украина http://rakafon.blogspot.com/
Дата: 14.10.09 11:45
Оценка: 1 (1) -2
Здравствуйте, pepsicoca, Вы писали:

P>Зная, что терминал не юникодный и зная, что нужно выводить кириллицу (это можно узнать из Юникодного кода кирилических символов) почему бы системе самой перед выводом кирилицы не сделать imbue той локали, которая нужна?


Вы думаете щазз здесь появится разработчики виндовой консоли и разраюботчики std::cout/std::wcout из мелкософта и начнуть объяснять технически детали и причины нереализации таковой фичи. Я ж говорю: виндовая консоль — гавно! Сделайте свою консоль с нативной поддержкой Unicod'а и возможностью писать шрифтом "Georgia", "Gigi" или "Kunstler Script", и будет вам счастье!

P>Этот пример печатает в файл только латинское hello. Причем не в Юникоде, а в ASCII. :-(


А собственно что Вас удивляет/огорчает? Это стандартное поведение: так и должно быть. Как я Вам уже писал здесь: forum/cpp/3567835.1.aspx
Автор: Rakafon
Дата: 13.10.09
, (кстати совсем непонятно, зачем вы создали новую тему? это такая спамерская черта характера?) так вот, как я Вам уже писал, реализаций Unicod'а есть масса, соответственно std::ifstream/std::ofstream понятия не имеет в какой именно из Unicode кодировок представлен файл, поэтому файл всегда рассматривается как последовательность байт, т.е. "char". Таковое поведение стандартно, и иначе и быть не может. И конечно, по умолчанию, в качестве кодировки для char* в файле используется ASCII. Для выполнения конвертации из файлового представления в представление в памяти (т.е. из char в wchar_t и наоборот) необходимо использовать специальные объекты — facet'ы. Как это делать, смотрите здесь: Standard file streams and std::locale.и здесь: How to read unicode text file in C++.

Если использование boost'овских facet'ов или написание своих facet'ов вам совсем не улыбается, или если задача является более сложной, чем просто конвертнуть ASCII в UTF-16, тогда работу с Unicode файлами всегда можно делать руками: ну например вы имеете файл, и вы знаете, что он закодирован в Unicode кодировке UTF-8, а вам надо его отобразить в некой системе работающей только с UTF-16 (ну скажем, передать текст в функцию, принимающую UTF-16 текст как аргумент wchar_t*), тогда вы, например используя библиотеку iconv, вычитываете файл, закодированный в кодировке UTF-8 в буффер char* B1, создаёте буфер char* B2 с достаточной ёмкостью, кодируете текст из UTF-8 в UTF-16 используя функции библиотеки iconv, затем получаете указатель wchar_t* wB2 = reinterpret_cast<wchar_t*>(B2), который уже отдаёте функции, принимающей UTF-16 текст как аргумент wchar_t*.
Опять же, если у Вас есть задача сохранить файл в Unicode, тогда необходимо уточнить требование: в какой именно из Unicode кодировок его сохранить, и, исходя из source данных выбрать алгоритм коныертации, конвертнуть и сохранить. На MS Windows для кодирования текста можно воспользоваться функциями MultiByteToWideChar/WideCharToMultiByte, однако библиотека iconv предоставляет более богатые возможности для кодирования текста.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
unicode
Re[2]: тысяча третий раз про Юникод
От: pepsicoca  
Дата: 14.10.09 11:55
Оценка:
Здравствуйте, K13, Вы писали:

P>>3. Если в экзешнике уже лежит Юникодная строка, почему кириллица не печатается без явного указания локали функцией imbue? Ведь по Юникоду однозначно определяется начертание символа. И чтобы напечатать Юникод локаль не нужна.


K13>потоки ввода-вывода работают с char. Без указания, какая именно кодировка является активной, не обойтись.


Эта информация содержится в каждом коде Юникода. То есть по коду Юникода можно понять, какой это язык и слазить в систему за соответствующим начертанием символа в соответствующую таблицу.

K13>"Переключать на ходу" нельзя -- иначе при пайпе/записи в файл нам надо вставлять мета-символы между символами сообщения, а делать это мы не вправе.


Не надо вставлять никакие символы. Надо получить начертание буквы и отобразить ее на экране. И вся необходимая информация об соответствии кода и буквы уже содержится в Юникодном коде символа. А при выводе в широкий файл надо честно вывести в этот широкий файл Юникодный код. А иначе зачем Юникод, если все равно локаль указывать надо?
Re[4]: тысяча третий раз про Юникод
От: Pavel Dvorkin Россия  
Дата: 14.10.09 12:18
Оценка:
Здравствуйте, Rakafon, Вы писали:

R>Вы думаете щазз здесь появится разработчики виндовой консоли и разраюботчики std::cout/std::wcout из мелкософта и начнуть объяснять технически детали и причины нереализации таковой фичи.


Исходники файловых потоков C++ открыты и поставляются вместе с компилятором

"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\crt\src\"fstream

>Сделайте свою консоль с нативной поддержкой Unicod'а и возможностью писать шрифтом "Georgia", "Gigi" или "Kunstler Script", и будет вам счастье!


Сделать свою консоль не удастся. Консольное окно не есть обычное окно.

>как я Вам уже писал, реализаций Unicod'а есть масса, соответственно std::ifstream/std::ofstream понятия не имеет в какой именно из Unicode кодировок представлен файл, поэтому файл всегда рассматривается как последовательность байт, т.е. "char". Таковое поведение стандартно, и иначе и быть не может. И конечно, по умолчанию, в качестве кодировки для char* в файле используется ASCII. Для выполнения конвертации из файлового представления в представление в памяти (т.е. из char в wchar_t и наоборот) необходимо использовать специальные объекты — facet'ы.


Я не знаю насчет потоков, просто не интересовался, но


In Visual C++ 2005, fopen supports Unicode file streams. A flag specifying the desired encoding may be passed to fopen when opening a new file or overwriting an existing file, like this:

fopen("newfile.txt", "rw, ccs=<encoding>");

Allowed values of the encoding include UNICODE, UTF-8, and UTF16-LE. If the file is already in existence and is opened for reading or appending, the Byte Order Mark (BOM) is used to determine the correct encoding. It is not necessary to specify the encoding with a flag. In fact, the flag will be ignored if it conflicts with the type of the file as indicated by the BOM. The flag is only used when no BOM is present or if the file is a new file. The following table summarizes the modes used in for various flags given to fopen and Byte Order Marks used in the file.



Думаю, что и для потоков нечто такое есть
With best regards
Pavel Dvorkin
Re[4]: тысяча третий раз про Юникод
От: pepsicoca  
Дата: 14.10.09 12:31
Оценка:
Здравствуйте, Rakafon, Вы писали:

R>Здравствуйте, pepsicoca, Вы писали:


P>>Зная, что терминал не юникодный и зная, что нужно выводить кириллицу (это можно узнать из Юникодного кода кирилических символов) почему бы системе самой перед выводом кирилицы не сделать imbue той локали, которая нужна?


R>Вы думаете щазз здесь появится разработчики виндовой консоли и разраюботчики std::cout/std::wcout из мелкософта и начнуть объяснять технически детали и причины нереализации таковой фичи.


Ну не до такой же степени. Вдумайтесь — Юникод специально был создан, чтобы не переключать локали. И вот после всего этого, чтобы вывести Юникодный символ нужно явно указать локаль? Зачем тогда Юникод было городить?

R>Я ж говорю: виндовая консоль — гавно! Сделайте свою консоль с нативной поддержкой Unicod'а и возможностью писать шрифтом "Georgia", "Gigi" или "Kunstler Script", и будет вам счастье!


P>>Этот пример печатает в файл только латинское hello. Причем не в Юникоде, а в ASCII.


R>А собственно что Вас удивляет/огорчает? Это стандартное поведение: так и должно быть. Как я Вам уже писал здесь: <span class='lineQuote level1'>R&gt;forum/cpp/3567835.1.aspx</span>
Автор: Rakafon
Дата: 13.10.09
, (кстати совсем непонятно, зачем вы создали новую тему? это такая спамерская черта характера?)


Там уже никто не читает.

R>так вот, как я Вам уже писал, реализаций Unicod'а есть масса, соответственно std::ifstream/std::ofstream понятия не имеет в какой именно из Unicode кодировок представлен файл, поэтому файл всегда рассматривается как последовательность байт, т.е. "char".


Это верно для std::ofstream. Для std::wofstream ожидаемое поведение не такое. Очевидно, что если std::ofstream работает с файлом как с последовательностью байт char, то std::wofstream должен работать с файлом как с последовательностью широких байт wchar_t.

R>Таковое поведение стандартно, и иначе и быть не может. И конечно, по умолчанию, в качестве кодировки для char* в файле используется ASCII. Для выполнения конвертации из файлового представления в представление в памяти (т.е. из char в wchar_t и наоборот) необходимо использовать специальные объекты — facet'ы. Как это делать, смотрите здесь: Standard file streams and std::locale.и здесь: How to read unicode text file in C++.


R>Если использование boost'овских facet'ов или написание своих facet'ов вам совсем не улыбается, или если задача является более сложной, чем просто конвертнуть ASCII в UTF-16, тогда работу с Unicode файлами всегда можно делать руками: ну например вы имеете файл, и вы знаете, что он закодирован в Unicode кодировке UTF-8, а вам надо его отобразить в некой системе работающей только с UTF-16 (ну скажем, передать текст в функцию, принимающую UTF-16 текст как аргумент wchar_t*), тогда вы, например используя библиотеку iconv, вычитываете файл, закодированный в кодировке UTF-8 в буффер char* B1, создаёте буфер char* B2 с достаточной ёмкостью, кодируете текст из UTF-8 в UTF-16 используя функции библиотеки iconv, затем получаете указатель wchar_t* wB2 = reinterpret_cast<wchar_t*>(B2), который уже отдаёте функции, принимающей UTF-16 текст как аргумент wchar_t*.

R>Опять же, если у Вас есть задача сохранить файл в Unicode, тогда необходимо уточнить требование: в какой именно из Unicode кодировок его сохранить, и, исходя из source данных выбрать алгоритм коныертации, конвертнуть и сохранить. На MS Windows для кодирования текста можно воспользоваться функциями MultiByteToWideChar/WideCharToMultiByte, однако библиотека iconv предоставляет более богатые возможности для кодирования текста.
Re[5]: тысяча третий раз про Юникод
От: Rakafon Украина http://rakafon.blogspot.com/
Дата: 14.10.09 12:44
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Исходники файловых потоков C++ открыты и поставляются вместе с компилятором
PD>"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\crt\src\"fstream

Ну, а вот реализацию виндовой консоли просто так не посмотреть ...


PD>Сделать свою консоль не удастся. Консольное окно не есть обычное окно.

Сделать свою консоль удастся. Это обычное дело: сделать собственную реализацию stdout из CRT, котороая вместо виндовой консоли будет плевать матюги в ваше окошечко (например в Edit Box), и в explorer shell встроить пунктик менюшки "открыть эту софтину в такой-то консоли", почле чего ваша кастомная консоль запустится, затем запустит целевую консольную софтину, после чего подменит ей stdin/stdout и другие потоки на свои. Я таких кастомноконсольных софтин пару штук видел. Собственно ничего космически сложного в таком таске не наблюдаю.


PD>fopen("newfile.txt", "rw, ccs=<encoding>");

PD>Allowed values of the encoding include UNICODE, UTF-8, and UTF16-LE. If the file is already in existence and is opened for reading or appending, the Byte Order Mark (BOM) is used to determine the correct encoding. It is not necessary to specify the encoding with a flag. In fact, the flag will be ignored if it conflicts with the type of the file as indicated by the BOM. The flag is only used when no BOM is present or if the file is a new file. The following table summarizes the modes used in for various flags given to fopen and Byte Order Marks used in the file.

А вот о такой зверюге никогда не слышал. Надо будет на досуге попробовать. Спасибо за инфу.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
unicode
Re[5]: тысяча третий раз про Юникод
От: Rakafon Украина http://rakafon.blogspot.com/
Дата: 14.10.09 13:36
Оценка:
Здравствуйте, pepsicoca, Вы писали:
P>Ну не до такой же степени. Вдумайтесь — Юникод специально был создан, чтобы не переключать локали. И вот после всего этого, чтобы вывести Юникодный символ нужно явно указать локаль? Зачем тогда Юникод было городить?

Юникод не был создан, чтобы "не переключать локали". Стандарты юникода были придуманы для создание единой «широкой» кодировки. При этом технически системе, чтобы уметь рисовать символы из определённого диапазона символов юникода (например кириллицу), необходимо иметь соответствующую локаль. При этом для разработчиков прикладного ПО важно просто использовать широкие символы, а то, будут ли они отображаться и как — перекладывается на плечи системы и пользователя, эту систему конфигурирующему: т.е. если приложение работает с испанским, французским, немецкими, русским и китайским языками, то оно просто использует широкие символы (UTF-16) внутри своих алгоритмов (ну или UTF-8 например), в то время как пользователь, ставящий такую софтину должен позаботиться о наличии испанской, французской, немецкой, русской и китайской локализации у себя в системе, иначе рискует ничего не увидеть или увидеть "квадратики" и прочие кракозябры. Вот ты возьми скачай китайскую юникодную софтину и проинсталь у себя и поделись с нами впечатлениями: у тебя же не стоит китайская локаль в системе, правда? Плюс, как теюе тут верно заметили, есть программы, не использующие юникод, для таких тоже есть свои настройки в системе: использование определённой локали. Если юникодной софтине достаточно просто наличие локали в системе, то неюникодную надо носом тыкать, мол юзай вот эту. Ну и консоль виндовая, походу неюникодная.




P>Там уже никто не читает.

Да ладно. Я читаю.




P>Это верно для std::ofstream. Для std::wofstream ожидаемое поведение не такое. Очевидно, что если std::ofstream работает с файлом как с последовательностью байт char, то std::wofstream должен работать с файлом как с последовательностью широких байт wchar_t.


Ничё он не должен: файл как был последовательностью байт, так таковой и остался, и завтра таким же будет. Поэтому если вы ожидаете от std::wofstream такого поведения, это вовсе не означает что он должен это делать так. Я вот ничего такого от него не ожидаю, я ожидаю от него только лишь стандартного поведения. А стандарт С++ заботится о переносимости стандартной С++ библиотеки между платформами.

Файл — это поток байт! Не важно что там за данные: текст в кодировке UTF-32, xml в кодировке UTF-8 или видеопоток MPEG4, файл остаётся последовательностью байт. Всегда! И если в файле не однобайтовый текст, а некие другие данные, то прикладному ПО надо эти данные прочитать и раскодировать в нужное представление в памяти. Текст в UTF-32 — это тоже "другие данные"! Если в файле на самом деле лежит текст в кодировке UTF-16, тогда этот поток байт надо правильно представить в памяти, для этого существуют библиотеки подобные libiconv или поддержка на уровне API операционной системы. Ещё раз: такое поведение стандартно и переносимо между всем чем только угодно. Если необходимо изменить это стандартное поведение — надо настраивать файловые потоки специальным образом. Точка.




P.S.: Видели фильм "День Независимости" c певцом-нигером в главной роли? Так вот возможность заразить нашей вируснёй инопланетные компы существовала именно благодаря тому что std::basic_ostream</*пофиг char или wchar_t*/> писал всё в файл не двубайтами, а только байтами, байтами, байтами ...

... шутка конечно: переносимость поведения std::basic_ostream<> зиждется только на том, что на всех возможных системах файл — есть последовательность байт, а байт — равен восьми битам, а бит может принимать только два состояния [on] и [off]. Если прилетит межгалактический корабль с пришельцами, которого их бит будет иметь три состояния [on] [median] [off], а байт состоять из 16 битов, то их, инопланетный std::basic_ostream<> будет несовместим с нашим std::basic_ostream<>, чтоб их совместить, придётся фасет специальный напедалить!

"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
unicode
Re[4]: тысяча третий раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 13:46
Оценка: 2 (1) +1 :)
Здравствуйте, Rakafon, Вы писали:

R>Вы думаете щазз здесь появится разработчики виндовой консоли и разраюботчики std::cout/std::wcout из мелкософта и начнуть объяснять технически детали и причины нереализации таковой фичи. Я ж говорю: виндовая консоль — гавно! Сделайте свою консоль с нативной поддержкой Unicod'а и возможностью писать шрифтом "Georgia", "Gigi" или "Kunstler Script", и будет вам счастье!


Ага, и сделайте, чтобы полноэкранная консоль под виндами тоже это умела!

И чтобы текстовый терминал в никсах тоже умел, и желательно без трюков с фреймбуфером, а прямо родным кодогенератором CGA-видяхи (со фреймбуфером он, кстати, умеет — только нужно бубен потолще выхватить).
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[6]: тысяча третий раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 13:46
Оценка: 4 (1) +1 :)
Здравствуйте, Rakafon, Вы писали:

PD>>Сделать свою консоль не удастся. Консольное окно не есть обычное окно.

R>Сделать свою консоль удастся. Это обычное дело: сделать собственную реализацию stdout из CRT, котороая вместо виндовой консоли будет плевать матюги в ваше окошечко (например в Edit Box), и в explorer shell встроить пунктик менюшки "открыть эту софтину в такой-то консоли", почле чего ваша кастомная консоль запустится, затем запустит целевую консольную софтину, после чего подменит ей stdin/stdout и другие потоки на свои. Я таких кастомноконсольных софтин пару штук видел. Собственно ничего космически сложного в таком таске не наблюдаю.
R>

Замучаешься реализовывать всю обвязку Console API. Она не исчерпывается функциями WriteConsole/ReadConsole.
А без обвязки приложение будет думать, что оно запущено в конвеерном, а не интерактивном режиме, и может повести себя совсем по-другому.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[6]: тысяча третий раз про Юникод
От: pepsicoca  
Дата: 14.10.09 13:55
Оценка:
Здравствуйте, Rakafon, Вы писали:

R>Здравствуйте, pepsicoca, Вы писали:

P>>Ну не до такой же степени. Вдумайтесь — Юникод специально был создан, чтобы не переключать локали. И вот после всего этого, чтобы вывести Юникодный символ нужно явно указать локаль? Зачем тогда Юникод было городить?

R>Юникод не был создан, чтобы "не переключать локали". Стандарты юникода были придуманы для создание единой «широкой» кодировки. При этом технически системе, чтобы уметь рисовать символы из определённого диапазона символов юникода (например кириллицу), необходимо иметь соответствующую локаль. При этом для разработчиков прикладного ПО важно просто использовать широкие символы, а то, будут ли они отображаться и как — перекладывается на плечи системы и пользователя, эту систему конфигурирующему: т.е. если приложение работает с испанским, французским, немецкими, русским и китайским языками, то оно просто использует широкие символы (UTF-16) внутри своих алгоритмов (ну или UTF-8 например), в то время как пользователь, ставящий такую софтину должен позаботиться о наличии испанской, французской, немецкой, русской и китайской локализации у себя в системе, иначе рискует ничего не увидеть или увидеть "квадратики" и прочие кракозябры. Вот ты возьми скачай китайскую юникодную софтину и проинсталь у себя и поделись с нами впечатлениями: у тебя же не стоит китайская локаль в системе, правда? Плюс, как теюе тут верно заметили, есть программы, не использующие юникод, для таких тоже есть свои настройки в системе: использование определённой локали. Если юникодной софтине достаточно просто наличие локали в системе, то неюникодную надо носом тыкать, мол юзай вот эту.


Воооот. И я о том же. Если в системе стоят шрифты соответствующего языка, то для wcout это исчерпывающая информация для работы. Для простого cout этого недостаточно, ему нужно еще явно указать, какой именно язык сейчас юзается.

R>Ну и консоль виндовая, походу неюникодная.


А wcout легко может (и должен) сделать ее юникодной. Просто по коду текущего Юникодного символа нужно делать imbue соответствующей локали.

R>



P>>Там уже никто не читает.

R>Да ладно. Я читаю.

А больше никто.

R>



P>>Это верно для std::ofstream. Для std::wofstream ожидаемое поведение не такое. Очевидно, что если std::ofstream работает с файлом как с последовательностью байт char, то std::wofstream должен работать с файлом как с последовательностью широких байт wchar_t.


R>Ничё он не должен: файл как был последовательностью байт, так таковой и остался, и завтра таким же будет. Поэтому если вы ожидаете от std::wofstream такого поведения, это вовсе не означает что он должен это делать так. Я вот ничего такого от него не ожидаю, я ожидаю от него только лишь стандартного поведения. А стандарт С++ заботится о переносимости стандартной С++ библиотеки между платформами.


Тогда скажите, чем отличается std::wofstream от std::ofstream? В Вашей формулировке они не отличаются ничем. Тогда какой смысл иметь std::wofstream, если он ничем не отличатется от std::ofstream?
Re[2]: тысяча третий раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 14:17
Оценка: 4 (1) +1
Здравствуйте, K13, Вы писали:

K13>it depends. Вот у нас за такой исходник можно получить по башке, потому что принято решение все исходники сохранять как UTF-8 без BOM.

K13>Иначе возникают проблемы на маке

На овощебазе совсем сдурели — БОМ не понимают?!


По-хорошему, не надо вообще запихивать локализованные строки в исходные тексты.
Хотя если программа делается под единственный конкретный человеческий язык, то сойдёт.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[7]: тысяча третий раз про Юникод
От: Rakafon Украина http://rakafon.blogspot.com/
Дата: 14.10.09 14:20
Оценка:
Здравствуйте, Кодт, Вы писали:
К>Замучаешься реализовывать всю обвязку Console API. Она не исчерпывается функциями WriteConsole/ReadConsole.
К>А без обвязки приложение будет думать, что оно запущено в конвеерном, а не интерактивном режиме, и может повести себя совсем по-другому.

Да я просто имею в виду, что проблема решаема. Другой вопрос: зачем?
Надо просто использовать нативную консоль и писать там по-английски.
А всякие "китайские" красивости предоставить юникодному гую.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Re[3]: тысяча третий раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 14:23
Оценка: 12 (2) +2 :)
Здравствуйте, pepsicoca, Вы писали:

P>Не надо вставлять никакие символы. Надо получить начертание буквы и отобразить ее на экране. И вся необходимая информация об соответствии кода и буквы уже содержится в Юникодном коде символа. А при выводе в широкий файл надо честно вывести в этот широкий файл Юникодный код. А иначе зачем Юникод, если все равно локаль указывать надо?


Зачем указывать локаль: у локали много граней (facet'ов) — это не только (мульти)байтовая кодировка, но ещё и формат чисел, списков, денег, и т.д.
Так что потоковому вводу-выводу информация о локали пригодится.

А вот зачем указывать кодировку... Тут проявляется разница между "текстовым" и "бинарным" режимами.
В текстовом режиме потоки ввода-вывода — (мульти)байтовые. Естественно, чтобы вывести юникодный текст — нужно его перевести.

Просто так, нахаляву, перейти на UTF-16 нельзя: подавляющее большинство программ исходит из того, что от них ждут байты, ==> консоль должна принимать байты, ==> новые программы тоже должны посылать байты. Порочный круг
Либо задействовать соответствующие API — Console API под виндами, curses (или что там на низком уровне?) под никсами.

А ведь всё могло бы быть совсем не так... если бы в древнем 95 году микрософт решил бы не UCS-2 использовать (да! про UTF-16 они спохватились в самый последний момент, когда на них посыпались багрепорты от китайцев), а UTF-8.
Заодно приучили бы программистов к грамотной работе с человекочитаемыми строками. Потому что даже UCS-4 не спасает от проблемы (символ != кодпойнт) — когда используются композиты.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[4]: тысяча третий раз про Юникод
От: matcode Беларусь  
Дата: 14.10.09 14:47
Оценка: 1 (1)
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, pepsicoca, Вы писали:


P>>Не надо вставлять никакие символы. Надо получить начертание буквы и отобразить ее на экране. И вся необходимая информация об соответствии кода и буквы уже содержится в Юникодном коде символа. А при выводе в широкий файл надо честно вывести в этот широкий файл Юникодный код. А иначе зачем Юникод, если все равно локаль указывать надо?


К>Зачем указывать локаль: у локали много граней (facet'ов) — это не только (мульти)байтовая кодировка, но ещё и формат чисел, списков, денег, и т.д.

К>Так что потоковому вводу-выводу информация о локали пригодится.

К>А вот зачем указывать кодировку... Тут проявляется разница между "текстовым" и "бинарным" режимами.

К>В текстовом режиме потоки ввода-вывода — (мульти)байтовые. Естественно, чтобы вывести юникодный текст — нужно его перевести.

К>Просто так, нахаляву, перейти на UTF-16 нельзя: подавляющее большинство программ исходит из того, что от них ждут байты, ==> консоль должна принимать байты, ==> новые программы тоже должны посылать байты. Порочный круг

К>Либо задействовать соответствующие API — Console API под виндами, curses (или что там на низком уровне?) под никсами.

К>А ведь всё могло бы быть совсем не так... если бы в древнем 95 году микрософт решил бы не UCS-2 использовать (да! про UTF-16 они спохватились в самый последний момент, когда на них посыпались багрепорты от китайцев), а UTF-8.

К>Заодно приучили бы программистов к грамотной работе с человекочитаемыми строками. Потому что даже UCS-4 не спасает от проблемы (символ != кодпойнт) — когда используются композиты.

На счет UTF-8 Microsoft конечно лажанулся. Сейчас бы намного меньше проблем с кроссплатформенностью было бы и никаких там GetTextA , GetTextW и TCHAR

Ну а UTF-16 и сейчас на консоль вывести можно начиная с Visual C++ 2005:


#include <io.h>
#include <fcntl.h>
#include <iostream>
using namespace std;

int main()
{
    _setmode(_fileno(stdout),_O_WTEXT);
    wcout<<L"Привет! Tschüß!"<<endl;
    return 0;
}


Только установить шрифт Lucida Console и нельзя использовать (мульти)байтовые функции(cout,printf и т.д.)
Re[4]: тысяча третий раз про Юникод
От: pepsicoca  
Дата: 14.10.09 14:52
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, pepsicoca, Вы писали:


P>>Не надо вставлять никакие символы. Надо получить начертание буквы и отобразить ее на экране. И вся необходимая информация об соответствии кода и буквы уже содержится в Юникодном коде символа. А при выводе в широкий файл надо честно вывести в этот широкий файл Юникодный код. А иначе зачем Юникод, если все равно локаль указывать надо?


К>Зачем указывать локаль: у локали много граней (facet'ов) — это не только (мульти)байтовая кодировка, но ещё и формат чисел, списков, денег, и т.д.

К>Так что потоковому вводу-выводу информация о локали пригодится.

К>А вот зачем указывать кодировку... Тут проявляется разница между "текстовым" и "бинарным" режимами.

К>В текстовом режиме потоки ввода-вывода — (мульти)байтовые. Естественно, чтобы вывести юникодный текст — нужно его перевести.

Ну и переводите сколько душе угодно. Но — автоматически, без моего участия. Для того и сделан wcout, чтобы все перевести и вывести как надо. А уж для cout, так и быть, согласен вручную переключать кодировки.

К>Просто так, нахаляву, перейти на UTF-16 нельзя: подавляющее большинство программ исходит из того, что от них ждут байты, ==> консоль должна принимать байты, ==> новые программы тоже должны посылать байты. Порочный круг

К>Либо задействовать соответствующие API — Console API под виндами, curses (или что там на низком уровне?) под никсами.

К>А ведь всё могло бы быть совсем не так... если бы в древнем 95 году микрософт решил бы не UCS-2 использовать (да! про UTF-16 они спохватились в самый последний момент, когда на них посыпались багрепорты от китайцев), а UTF-8.

К>Заодно приучили бы программистов к грамотной работе с человекочитаемыми строками. Потому что даже UCS-4 не спасает от проблемы (символ != кодпойнт) — когда используются композиты.

UTF-8 просто по-другому кодирует тот же Юникод. Так что проблемы композитов остаются.
Re[7]: тысяча третий раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 14:54
Оценка: 1 (1) :)
Здравствуйте, pepsicoca, Вы писали:

P>А wcout легко может (и должен) сделать ее юникодной. Просто по коду текущего Юникодного символа нужно делать imbue соответствующей локали.


Не надо ему ничего на лету подкручивать.
Всё, что ему нужно делать — это, наоборот, не заниматься трансляцией UTF-16 в байтовые кодировки — ни самому, ни нижележащим слоям CRT.
А обеспечить движение данных к функции WriteConsoleW вместо WriteFile или WriteConsoleA.

P>Тогда скажите, чем отличается std::wofstream от std::ofstream? В Вашей формулировке они не отличаются ничем. Тогда какой смысл иметь std::wofstream, если он ничем не отличатется от std::ofstream?


Он (точнее, не он сам, а putws — фасадом к которому он выступает) умеет доводить до вызовов WriteConsoleW. Но ты ему сперва в ножки поклонишься.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[7]: тысяча третий раз про Юникод
От: Rakafon Украина http://rakafon.blogspot.com/
Дата: 14.10.09 15:52
Оценка: 3 (1)
Здравствуйте, pepsicoca, Вы писали:
P>Тогда скажите, чем отличается std::wofstream от std::ofstream? В Вашей формулировке они не отличаются ничем. Тогда какой смысл иметь std::wofstream, если он ничем не отличатется от std::ofstream?

Смысл в том, чтобы открыть файл с содержанием "Hello World!!!" (в кодировке ASCII), и прочитать эту строчку в std::wstring с помощью std::wofstream, созданного без флага std::ios::binary, чтобы можно было потом отдать её (std::wstring строку) туда, где хотят wchar_t* текст. Т.е. если в софтине вы используете широкие строки, то пользуется std::wstring/std::wofstream/std::wifstream/std::wstringstream, если в софтине вы используете однобайтовые строки, то используете std::string/std::ofstream/std::ifstream/std::stringstream соответственно. При этом и std::ofstream и std::wofstream будет подразумевать, что в файле лежит однобайтовый текст, закодированный в активной системной локали, просто внутри программы они будут оперировать с разными символами char и wchar_t соответственно.

Как вы наверняка знаете, std::basic_ofstream/std::basic_ifstream могут работать в двух режимах: текстовом и бинарном. Это определяется отсутствием или наличием флага std::ios::binary соответственно. Текстовый режим работает по умолчанию. Бинарный включается руками во время конструирования или во время вызова метода open(). Если std::basic_ofstream работает в текстовом режиме, то он вправе изменять переданные строки перед сохранием, например он заменяет символ '\n' на последовательность символов "\r\n" на винде, на символ '\n' на Линуксе и на символ '\r' на маке. То же саме для std::basic_ifstream, только в обратную сторону. Если std::basic_ofstream работает в бинарном режиме, то он просто пишет то что ему дали и всё.

Текстовыми файлами являются файлы которые содержат данные в однобайтовой кодировке, например ASCII. Остальные файлы являются бинарными: то есть для их корректного чтения и правильного представления в памяти необходимы соответствующие алгоритмы. Если в файле хранится юникод-текст в кодировке UTF-8, то в самом начале файла лежит сигнатура, состоящая из байтов EF BB BF, если в кодировке UTF-16BE, то сигнатура — FE FF, если UTF-16LE — FF FE, если UTF-32BE или UTF-32LE, то 00 00 FE FF и FF FE 00 00. Так вот эти сигнатуры "говорят" нам: "мы не просто текстовые файлы, мы файлы с некими данными, хранящимися в определённом формате, и чтобы работать с этими данными, вам понадобятся определённые алгоритмы".

Чтобы прочитать простой текстовый файл программе, использующей char* строки, необходимо:
  • открыть этот файл с помощью std::ifstream
  • возможно, потребуется сделать вызов strm.unsetf(std::ios::skipws), чтобы не поскипать пробелы, табуляции, переходы строк и прочие пустые символы
  • читать оттуда строки и помещать их в char* контейнер, например в std::string

    Чтобы записать простой текстовый файл программе, использующей char* строки, необходимо:
  • открыть этот файл с помощью std::оfstream
  • писать туда строки из char* контейнеров, например из std::string

    Чтобы прочитать простой текстовый файл программе, использующей wchar_t* строки, необходимо:
  • открыть этот файл с помощью std::wifstream
  • возможно, потребуется сделать вызов strm.unsetf(std::ios::skipws), чтобы не поскипать пробелы, табуляции, переходы строк и прочие пустые символы
  • читать оттуда строки и помещать их в wchar_t* контейнер, например в std::wstring

    Чтобы записать простой текстовый файл программе, использующей wchar_t* строки, необходимо:
  • открыть этот файл с помощью std::wоfstream
  • писать туда строки из wchar_t* контейнеров, например из std::wstring

    Чтобы прочитать бинарный файл программе, не важно какие строки использующей, необходимо:
  • открыть этот файл с помощью std::ifstream, указав флаг std::ios::binary
  • hint: при этом не надо использовать std::wifstream для этих целей, потому что каждый байт файла будет помещён в wchar_t переменную, что логически не верно (я не знаю точно таким ли будет поведение std::wifstream, однако предпочитаю и советую использовать для бинарного чтения узкие потоковые классы)
  • не помню, надо ли здесь strm.unsetf(std::ios::skipws) делать :)
  • читать оттуда блоки данных и помещать их в char* контейнер
  • работать с этими данными

    Чтобы записать бинарный файл программе, не важно какие строки использующей, необходимо:
  • открыть этот файл с помощью std::оfstream, указав флаг std::ios::binary
  • hint: при этом не надо использовать std::wоfstream для этих целей, потому что каждое двубайтие будет впихнуто только в один байт при записи в файл, при этом будет происходить потеря старшего байта двубайтия (я не знаю точно таким ли будет поведение std::wоfstream, однако предпочитаю и советую использовать для бинарной записи узкие потоковые классы)
  • записать туда бинарные данные, взятые из char* контейнера

    Чтобы прочитать юникодный текстовый файл программе, использующей char* строки, необходимо:
  • открыть этот файл с помощью std::ifstream
  • узнать кодировку этого файла, используя хранящуююся в начале соответствующую сигнатуру (или если её там нет, то тогда софтина должна "знать" в какой unicode-кодировке ей подсунули текст, например она может спросить это у юзверя)
  • возможно, потребуется сделать вызов strm.unsetf(std::ios::skipws), чтобы не поскипать пробелы, табуляции, переходы строк и прочие пустые символы
  • читать оттуда строки и помещать их в char* контейнер, например в std::vector<[i]char*>[/i]
  • транслировать полученные данные из известной кодировки (UTF-8/UTF-16BE/UTF-16LE/etc.) в текстовую кодировку, с которой работает программа, например CP1251, при этом символы, эквивалента которых нет в целевой кодировке (например CP1251) будут заменены какой-то хернёй; результат поместить в в char* контейнер, например в std::string
  • работать с полученным однобайтовым текстом

    Чтобы записать юникодный текстовый файл программе, использующей char* строки, необходимо:
  • открыть этот файл с помощью std::оfstream
  • транслировать свои данные из кодировки, с которой работает программа, в нужную кодировку (UTF-8/UTF-16BE/UTF-16LE/etc.) и поместить результат в char* контейнер, например std::vector<[i]char*>[/i]
  • записать в начало файла сигнатуру нужной out кодировки (например для UTF-8 -> EF BB BF)
  • писать в файл данные из полученного char* контейнера, в котором хранится юникодный текст

    Чтобы прочитать юникодный текстовый файл программе, использующей wchar_t* строки, необходимо:
  • открыть этот файл с помощью std::ifstream
  • узнать кодировку этого файла, используя хранящуююся в начале соответствующую сигнатуру (или если её там нет, то тогда софтина должна "знать" в какой unicode-кодировке ей подсунули текст, например она может спросить это у юзверя)
  • возможно, потребуется сделать вызов strm.unsetf(std::ios::skipws), чтобы не поскипать пробелы, табуляции, переходы строк и прочие пустые символы
  • читать оттуда строки и помещать их в char* контейнер, например в std::vector<[i]char*>[/i]
  • транслировать полученные данные из известной кодировки (UTF-8/UTF-16BE/UTF-16LE/etc.) в текстовую кодировку, с которой работает программа, например USC-2 на винде позднее Windows NT или UTF-16LE на винде позднее Windows 2000, результат поместить в в wchar_t* контейнер, например в std::wstring
  • работать с полученным двубайтовым текстом

    Чтобы записать юникодный текстовый файл программе, использующей wchar_t* строки, необходимо:
  • открыть этот файл с помощью std::оfstream
  • транслировать свои wchar_t* строки из кодировки, с которой работает программа (например USC-2 на винде позднее Windows NT или UTF-16LE на винде позднее Windows 2000), в нужную кодировку (UTF-8/UTF-16BE/UTF-16LE/etc.) и поместить результат в char* контейнер, например std::vector<[i]char*>[/i]
  • записать в начало файла сигнатуру нужной out кодировки (например для UTF-16LE -> FF FE)
  • писать в файл данные из полученного char* контейнера, в котором хранится юникодный текст

    Для того чтобы и на входе (чтение unicode-текста из файлов), и на выходе (запись unicode-текста в файлы), и внутри алгоритмов программы поддержать не все возможные кодировки Юникода (UTF-8/UTF-16BE/UTF-16LE/etc.), а только лишь одну широкую кодировку (например нативную для винды — UTF-16LE), и при этом пользовать потоковые широкие классы, люди конфигурируют свои широкие потоковые классы с помощью фацетов и локалей, примерно как здесь: standard-file-streams-and-stdlocale_20.html или здесь: read-unicode-text-file-in-c.html. При этом, конечно, теряется вся гибкость работы с Unicode-кодировками, т.е. программа, использующая std::wstring и отконфигурированные std::wofstream и std::wifstream, и работающая на Windows 2000 and later, может писать и читать только в кодировке UTF-16LE, и если ей потребуется записать/почитать текст в другой unicode-кодировке (UTF-8/UTF-16BE/USC-2/UTF-32BE/UTF-32LE/etc.), то ей придётся заморочиться с пунктами, приведенными выше.

    Возврящаясь к нашим баранам. Т.е. к консоли. Если консоль — есть главное устройство ввода/вывода и интеракции с пользователем, как в GNU/Linux например, то ей по статусу положено быть навороченной, писать текст всеми цветами радуги, в локальной кодировке и в кодировках Юникода и пр. Если же консоль — аппендикс операционки, пережиток времён DOS'а, и главным устройством ввода/вывода и интеракции с пользователем является ГУЙ, как в винде например, тогда такой консоли по статусу не положено быть навороченной. Т.е. вы можете представить себе консоль, как простой текстовый файл, данные в котором хранятся в активной в системе локальной однобайтовой кодировке. У винды с русской локализацией (CP1251) консоль работает в кодировке DOS-866? чтобы поддержать всякой досовское старьё видимо. Соответственно для того чтобы std::wcout, который как мы знаем на винде с активной русской локалью CP1251 пишет текст в кодировке CP1251, для того чтобы std::wcout мог внятно по-русски написать в консоль, надо ему подсказать, что данные, которые ему заходят через оператор << в текстовой кодировке CP1251, в целевом файле (т.е. в консоли) должны сидеть в кодировке DOS-866, а не в кодировке CP1251, и это достигается вызовом std::wcout.imbue(std::locale("rus_rus.866"));. Вот в принципе и всё.


  • "Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
    unicode
    Re[8]: тысяча третий раз про Юникод
    От: Rakafon Украина http://rakafon.blogspot.com/
    Дата: 14.10.09 16:10
    Оценка:
    Здравствуйте, Rakafon, Вы писали:
    R>У винды с русской локализацией (CP1251) консоль работает в кодировке DOS-86. Чтобы поддержать всякой досовское старьё видимо. Соответственно для того чтобы std::wcout, который как мы знаем на винде с активной русской локалью CP1251 пишет текст в кодировке CP1251, для того чтобы std::wcout мог внятно по-русски написать в консоль, надо ему подсказать, что данные, которые ему заходят через оператор << в текстовой кодировке CP1251, в целевом файле (т.е. в консоли) должны сидеть в кодировке DOS-866, а не в кодировке CP1251, и это достигается вызовом std::wcout.imbue(std::locale("rus_rus.866"));.

    Тут ошибка, должно быть так:

    У винды с русской локализацией (CP1251) консоль работает в кодировке DOS-866. Чтобы поддержать всякой досовское старьё видимо.
    Все потоковые классы, в том числе и std::wcout, по умолчанию пишут в простой текстовый файл, в том числе и в консоль. Соответственно для того чтобы std::wcout, который как мы знаем на винде с активной русской локалью CP1251 пишет текст в кодировке CP1251, для того чтобы std::wcout мог внятно по-русски написать в консоль, надо ему подсказать, что данные, которые ему заходят через оператор << в текстовой кодировке UTF-16LE, в целевом файле (т.е. в консоли) должны сидеть не в кодировке CP1251 (как обычно), а в кодировке DOS-866, и это достигается вызовом [i]std::wcout.imbue(std::locale("rus_rus.866"));
    "Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
    Re[2]: тысяча третий раз про Юникод
    От: Sergey Chadov Россия  
    Дата: 14.10.09 17:39
    Оценка:
    Здравствуйте, andrey.desman, Вы писали:


    P>>2. Если в исходнике будет несколько сообщений "привет" на разных языках, то как транслятор сформирует Юникод для каждого из них? Откуда он узнает локаль текущего сообщения?


    AD>В исходнике не может быть нескольких сообщений на разных языках, потому что ты ограничен таблицей cp1251. Если конечно сам исходник не в юникоде записан. Правда я не знаю, поддерживает ли студия компиляцию юникодных исходников.


    поддерживает.
    --
    Sergey Chadov

    ... << RSDN@Home 1.2.0 alpha rev. 685>>
    Re[4]: тысяча третий раз про Юникод
    От: Sergey Chadov Россия  
    Дата: 14.10.09 17:39
    Оценка: +1
    Здравствуйте, Rakafon, Вы писали:


    R>Вы думаете щазз здесь появится разработчики виндовой консоли и разраюботчики std::cout/std::wcout из мелкософта и начнуть объяснять технически детали и причины нереализации таковой фичи. Я ж говорю: виндовая консоль — гавно! Сделайте свою консоль с нативной поддержкой Unicod'а и возможностью писать шрифтом "Georgia", "Gigi" или "Kunstler Script", и будет вам счастье!


    Консоль, как и вся остальная винда вполне юникодная. Только вот шрифт там по-умолчанию стоит неюникодный.
    --
    Sergey Chadov

    ... << RSDN@Home 1.2.0 alpha rev. 685>>
    Re: тысяча третий раз про Юникод
    От: _DAle_ Беларусь  
    Дата: 14.10.09 18:19
    Оценка:
    Здравствуйте, pepsicoca, Вы писали:

    P>3. Если в экзешнике уже лежит Юникодная строка, почему кириллица не печатается без явного указания локали функцией imbue? Ведь по Юникоду однозначно определяется начертание символа. И чтобы напечатать Юникод локаль не нужна.


    http://www.rsdn.ru/forum/cpp/645589.1.aspx
    Автор: MaximE
    Дата: 18.05.04


    P>Спасибо.
    Re[2]: тысяча третий раз про Юникод
    От: MasterZiv СССР  
    Дата: 14.10.09 19:00
    Оценка: -1
    jazzer пишет:

    > В качестве дикого предположения (я под винду не программирую)...

    > Ты ведь, наверное, имеешь в виду, что не печатает в терминале? Так он не
    > юникодный, скорее всего.

    Я ему это уже раза два писал. Видимо, бесполезно.
    Posted via RSDN NNTP Server 2.1 beta
    Re[3]: тысяча третий раз про Юникод
    От: MasterZiv СССР  
    Дата: 14.10.09 19:02
    Оценка: -2
    pepsicoca пишет:

    > Зная, что терминал не юникодный и зная, что нужно выводить кириллицу

    > (это можно узнать из Юникодного кода кирилических символов) почему бы
    > системе самой перед выводом кирилицы не сделать imbue той локали,
    > которая нужна?

    Потому что это винда. Там терминалы на фиг никому не нужны,
    только экзотам типа юниксоидов, пользующих cygwin или MinGW-Sys,
    но у них и свои консоли имеются. Кстати, в cygwin есть и юникодная,
    почему бы тебе ею не воспользоваться ?
    Posted via RSDN NNTP Server 2.1 beta
    Re[4]: тысяча третий раз про Юникод
    От: MasterZiv СССР  
    Дата: 14.10.09 19:09
    Оценка:
    Rakafon пишет:

    > Вы думаете щазз здесь появится разработчики виндовой консоли и

    > разраюботчики /std::cout///std::wcout/ из мелкософта и начнуть объяснять
    > технически детали и причины нереализации таковой фичи. Я ж говорю:
    > виндовая консоль — гавно! Сделайте свою консоль с нативной поддержкой
    > Unicod'а и возможностью писать шрифтом "Georgia", "Gigi" или "Kunstler
    > Script", и будет вам счастье!

    Главное, дело вовсе не в невозможности создать это чудо.
    В винде просто тупо не найдётся таких приложений, чтобы работали
    в этом режиме. Это ж надо ! Юникодное приложение, не оконное,
    а потоковое, и ещё что-то пишущее активно в консоль.

    FAR разве что ... Да он сам консолью правит.
    Posted via RSDN NNTP Server 2.1 beta
    Re[5]: тысяча третий раз про Юникод
    От: Cyberax Марс  
    Дата: 14.10.09 19:18
    Оценка:
    Здравствуйте, Кодт, Вы писали:

    К>И чтобы текстовый терминал в никсах тоже умел, и желательно без трюков с фреймбуфером, а прямо родным кодогенератором CGA-видяхи (со фреймбуфером он, кстати, умеет — только нужно бубен потолще выхватить).

    С KMS бубна уже не нужно.
    Sapienti sat!
    Re[3]: тысяча третий раз про Юникод
    От: IID Россия  
    Дата: 14.10.09 22:47
    Оценка:
    Здравствуйте, MasterZiv, Вы писали:

    MZ>jazzer пишет:


    >> В качестве дикого предположения (я под винду не программирую)...

    >> Ты ведь, наверное, имеешь в виду, что не печатает в терминале? Так он не
    >> юникодный, скорее всего.

    MZ>Я ему это уже раза два писал. Видимо, бесполезно.


    Консоль в винде уникодная. Но ты прав, бесполезно писать бред. Причём неважно сколько раз.
    kalsarikännit
    Re[3]: тысяча третий раз про Юникод
    От: jazzer Россия Skype: enerjazzer
    Дата: 15.10.09 02:41
    Оценка:
    Здравствуйте, Sergey, Вы писали:

    S>Заметно, что под винду не программируешь. С файлами в VC вообще жесткий прикол — они по умолчанию из широких строк в узкие конвертируют.


    жесть какая
    jazzer (Skype: enerjazzer) Ночная тема для RSDN
    Автор: jazzer
    Дата: 26.11.09

    You will always get what you always got
      If you always do  what you always did
    Re[8]: тысяча третий раз про Юникод
    От: pepsicoca  
    Дата: 15.10.09 06:55
    Оценка:
    Здравствуйте, Rakafon, Вы писали:

    Объем работы просто впечатляет.

    АднакА есть несколько возражений против нарисованной картины мира ввода-вывода.

    Нормальный человек ожидает, что std::fstream будет читать/писать из файла объекты char.
    Также нормальный человек ожидает, что std::wfstream будет читать/писать из файла объекты wchar_t.

    Опять же нормальный человек ожидает, что поведение этих потоков по отношению к char и wchar_t будет симметричным. То есть "побайтовое" чтение из std::fstream будет доставать из потока char за одно чтение, а "побайтовое" чтение из std::wfstream будет доставать из потока wchar_t за одно чтение.

    АднакА почему-то нестандартно мыслящие разработчики ввода-вывода сделали так, что "побайтовое" чтение из std::wfstream достает из широкого потока char за одно чтение.

    Может меня подводит мое чувство симметрии, но мне кажется, что это неправильно. И главное, непонятно, зачем это сделано. Если мне надо подергать файл побайтово, я всегда могу открыть его узким потоком и подергать его побайтово.

    С уважением...
    Re[4]: тысяча третий раз про Юникод
    От: _DAle_ Беларусь  
    Дата: 15.10.09 08:10
    Оценка:
    Здравствуйте, jazzer, Вы писали:

    J>Здравствуйте, Sergey, Вы писали:


    S>>Заметно, что под винду не программируешь. С файлами в VC вообще жесткий прикол — они по умолчанию из широких строк в узкие конвертируют.


    J>жесть какая


    Это не столько в VC, сколько в stl вообще.
    Re[5]: тысяча третий раз про Юникод
    От: Sergey Россия  
    Дата: 15.10.09 08:45
    Оценка:
    Здравствуйте, _DAle_, Вы писали:

    S>>>Заметно, что под винду не программируешь. С файлами в VC вообще жесткий прикол — они по умолчанию из широких строк в узкие конвертируют.


    J>>жесть какая


    _DA>Это не столько в VC, сколько в stl вообще.


    Насколько я знаю, в стандарте это вообще не регламентируется. Ну а под виндой лично я просто использую codecvt_null из бустовых архивов.
    Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
    Re[9]: тысяча третий раз про Юникод
    От: Rakafon Украина http://rakafon.blogspot.com/
    Дата: 15.10.09 08:56
    Оценка: -1
    Здравствуйте, pepsicoca, Вы писали:
    P>Нормальный человек ожидает, что std::fstream будет читать/писать из файла объекты char.
    P>Также нормальный человек ожидает, что std::wfstream будет читать/писать из файла объекты wchar_t.

    Нормальный человек ожидает, что с файловыми потоками можно работать либо в текстовом режиме, либо в бинарном.
    Если файловый поток работает в бинарном режиме, то на входе/выходе конфигурируют байтыю Именно байты, а не двубайтия или какие другие структуры данных. Именно поэтому нелогично использовать широкие потокы для бинарного доступа к файловому содержимому. Если файловый поток работает в текстовом режиме, то на выходе в файл и на входе из файла всегда конфигурируют символы, размер которых равен одному байту. Одному байту. Так устроены текстовые файлы. Если в файле "сидит", что-то другое, то это не текстовый файл, а файл с определённым образом закодированными данными со своей уникальной структурой, и значит такие данные надо выдирать из файла через бинарный доступ к нему. Файлы, в которых "сидит" текст, каждый символ которого занимает более байта, не являются текстовыми файлами.


    P>Опять же нормальный человек ожидает, что поведение этих потоков по отношению к char и wchar_t будет симметричным. То есть "побайтовое" чтение из std::fstream будет доставать из потока char за одно чтение, а "побайтовое" чтение из std::wfstream будет доставать из потока wchar_t за одно чтение.


    Нормальный человек ожидает, что работа с файлом будет происходить всегда единобразно: то есть побайтово! И по фиг при этом какие специализации потоковых классов std::basic_ofstream/std::basic_ifstream при этом используются! И если в файле располагаются не текстовые данные (а таковыми являются только мультибайтовые строки), то с файлом работают в бинарном режиме, доставая оттуда по байтику и конвертируя полученное добро в необходимое представление в памяти: то же саме касается и двубайтовых строк.


    P>АднакА почему-то нестандартно мыслящие разработчики ввода-вывода сделали так, что "побайтовое" чтение из std::wfstream достает из широкого потока char за одно чтение.


    Наоборот, так сделали разработчики со "стандартным" образом мышления, которые не нарушили концепцию, существующую ещё до нашей эры: древние египтяне тоже читали свои файлы побайтово! Когда потоковый класс работает с файлом, он работает с ним побайтово! И неважно во что он потом кастит каждый байт: в char, unsigned char, signed char, wchar_t, unsigned wchar_t, signed wchar_t, int, short int, long, etc. std::ifstream каждый байт кастит в char, std::wifstream каждый байт кастит в wchar_t. Если разработчик хочет, чтобы результат каждого чтения байта из файла был помещён в переменную, равную размеру байту, он использует std::ifstream. Если разработчик хочет нарушить существующую ещё с древнеегипетских времён концепцию: заставить потоковый класс читать сразу по два байта, в то время как его (потоковый класс) просят прочитать только один байт, он берёт std::wifstream и начинает издеваться над ним с помощью всякий фацетов. Иногда это оправдано. И если разработчику надо из фала вычитать unsigned int, значит ему надо sizeof(unsigned int) раз вычитать из фала по байтику и сложить это добро в переменную unsigned int, и воспользоваться при этом потоковым классом со стандартным поведением, который каждый раз вычитывая по байтику, будет результат складывать в переменную, равную по размерам байта.


    P>Может меня подводит мое чувство симметрии, но мне кажется, что это неправильно. И главное, непонятно, зачем это сделано. Если мне надо подергать файл побайтово, я всегда могу открыть его узким потоком и подергать его побайтово.


    Не знаю насчёт вашего чувства симметрии, но ИМХО: вы путаете тёплое с мягким: с файлами всегда работают побайтово.


    С Уважением.

    "Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
    unicode
    Re[3]: тысяча третий раз про Юникод
    От: alsemm Россия  
    Дата: 15.10.09 11:11
    Оценка:
    Здравствуйте, pepsicoca, Вы писали:

    P>Здравствуйте, K13, Вы писали:


    P>>>3. Если в экзешнике уже лежит Юникодная строка, почему кириллица не печатается без явного указания локали функцией imbue? Ведь по Юникоду однозначно определяется начертание символа. И чтобы напечатать Юникод локаль не нужна.


    K13>>потоки ввода-вывода работают с char. Без указания, какая именно кодировка является активной, не обойтись.


    P>Эта информация содержится в каждом коде Юникода. То есть по коду Юникода можно понять, какой это язык и слазить в систему за соответствующим начертанием символа в соответствующую таблицу.

    Что это за таблица такая волшебная?
    Re[10]: тысяча третий раз про Юникод
    От: pepsicoca  
    Дата: 15.10.09 12:11
    Оценка:
    Здравствуйте, Rakafon, Вы писали:

    R>Здравствуйте, pepsicoca, Вы писали:

    P>>Нормальный человек ожидает, что std::fstream будет читать/писать из файла объекты char.
    P>>Также нормальный человек ожидает, что std::wfstream будет читать/писать из файла объекты wchar_t.

    R>Нормальный человек ожидает, что с файловыми потоками можно работать либо в текстовом режиме, либо в бинарном.

    R>Если файловый поток работает в бинарном режиме, то на входе/выходе конфигурируют байтыю Именно байты, а не двубайтия или какие другие структуры данных. Именно поэтому нелогично использовать широкие потокы для бинарного доступа к файловому содержимому. Если файловый поток работает в текстовом режиме, то на выходе в файл и на входе из файла всегда конфигурируют символы, размер которых равен одному байту. Одному байту. Так устроены текстовые файлы. Если в файле "сидит", что-то другое, то это не текстовый файл, а файл с определённым образом закодированными данными со своей уникальной структурой, и значит такие данные надо выдирать из файла через бинарный доступ к нему. Файлы, в которых "сидит" текст, каждый символ которого занимает более байта, не являются текстовыми файлами.

    Так можно дойти до бита. Объявить бит единой и неделимой единицей информации (кстати, так оно и есть) и объявить, что файлы должны читаться побитно. А все, кто хочет строить какие-то более сложные структуры из файлов должны читать файл побитно и потом ручками эти структуры восстанавливать.

    P>>Опять же нормальный человек ожидает, что поведение этих потоков по отношению к char и wchar_t будет симметричным. То есть "побайтовое" чтение из std::fstream будет доставать из потока char за одно чтение, а "побайтовое" чтение из std::wfstream будет доставать из потока wchar_t за одно чтение.


    R>Нормальный человек ожидает, что работа с файлом будет происходить всегда единобразно: то есть побайтово! И по фиг при этом какие специализации потоковых классов std::basic_ofstream/std::basic_ifstream при этом используются! И если в файле располагаются не текстовые данные (а таковыми являются только мультибайтовые строки), то с файлом работают в бинарном режиме, доставая оттуда по байтику и конвертируя полученное добро в необходимое представление в памяти: то же саме касается и двубайтовых строк.



    P>>АднакА почему-то нестандартно мыслящие разработчики ввода-вывода сделали так, что "побайтовое" чтение из std::wfstream достает из широкого потока char за одно чтение.


    R>Наоборот, так сделали разработчики со "стандартным" образом мышления, которые не нарушили концепцию, существующую ещё до нашей эры: древние египтяне тоже читали свои файлы побайтово! Когда потоковый класс работает с файлом, он работает с ним побайтово! И неважно во что он потом кастит каждый байт: в char, unsigned char, signed char, wchar_t, unsigned wchar_t, signed wchar_t, int, short int, long, etc. std::ifstream каждый байт кастит в char, std::wifstream каждый байт кастит в wchar_t. Если разработчик хочет, чтобы результат каждого чтения байта из файла был помещён в переменную, равную размеру байту, он использует std::ifstream. Если разработчик хочет нарушить существующую ещё с древнеегипетских времён концепцию: заставить потоковый класс читать сразу по два байта, в то время как его (потоковый класс) просят прочитать только один байт, он берёт std::wifstream и начинает издеваться над ним с помощью всякий фацетов.


    И что, внутри фасцета я могу рекурсивно вызвать повторное чтение, чтобы считать дополнительный байт и уложить его во вторую половину wchar_t?

    R>Иногда это оправдано. И если разработчику надо из фала вычитать unsigned int, значит ему надо sizeof(unsigned int) раз вычитать из фала по байтику и сложить это добро в переменную unsigned int, и воспользоваться при этом потоковым классом со стандартным поведением, который каждый раз вычитывая по байтику, будет результат складывать в переменную, равную по размерам байта.



    P>>Может меня подводит мое чувство симметрии, но мне кажется, что это неправильно. И главное, непонятно, зачем это сделано. Если мне надо подергать файл побайтово, я всегда могу открыть его узким потоком и подергать его побайтово.


    R>Не знаю насчёт вашего чувства симметрии, но ИМХО: вы путаете тёплое с мягким: с файлами всегда работают побайтово.


    Плохая концепция. С байтовыми файлами надо работать побайтово. С файлами широких байтов надо работать "поширокобайтово". С файлами, в которые упакованы другие типы надо работать по единицам этих типов.

    И вообще, если пишут:

    typedef basic_ofstream<myType, char_traits<myType> > myTypeofstream;

    то единицей записи в таком файле должен быть не байт, а тип myType. А иначе весь смысл шаблонов теряется.


    R>С Уважением.


    R>
    Re[4]: тысяча третий раз про Юникод
    От: pepsicoca  
    Дата: 15.10.09 12:13
    Оценка:
    Здравствуйте, alsemm, Вы писали:

    A>Здравствуйте, pepsicoca, Вы писали:


    P>>Здравствуйте, K13, Вы писали:


    P>>>>3. Если в экзешнике уже лежит Юникодная строка, почему кириллица не печатается без явного указания локали функцией imbue? Ведь по Юникоду однозначно определяется начертание символа. И чтобы напечатать Юникод локаль не нужна.


    K13>>>потоки ввода-вывода работают с char. Без указания, какая именно кодировка является активной, не обойтись.


    P>>Эта информация содержится в каждом коде Юникода. То есть по коду Юникода можно понять, какой это язык и слазить в систему за соответствующим начертанием символа в соответствующую таблицу.

    A>Что это за таблица такая волшебная?

    Ну где там винда хранит начертание символов? В шрифтах наверное. Значит в шрифт.
    Re[5]: тысяча третий раз про Юникод
    От: Кодт Россия  
    Дата: 15.10.09 12:48
    Оценка:
    Здравствуйте, pepsicoca, Вы писали:

    P>Ну где там винда хранит начертание символов? В шрифтах наверное. Значит в шрифт.


    Плакать уже хочется, как мы плавно от STL и CRT перешли к шрифтовым движкам... И это всё — ведомство Си/С++?
    ... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
    Перекуём баги на фичи!
    Re[11]: тысяча третий раз про Юникод
    От: Sergey Россия  
    Дата: 15.10.09 12:49
    Оценка:
    Здравствуйте, pepsicoca, Вы писали:

    P>И что, внутри фасцета я могу рекурсивно вызвать повторное чтение, чтобы считать дополнительный байт и уложить его во вторую половину wchar_t?


    Если говорить про ввод, то используется вот такая функция:

    virtual result do_in(
         StateType& _State,
          const Byte* _First1, 
           const Byte* _Last1, 
         const Byte*& _Next1,
          CharType* _First2,
           CharType* _Last2,
          CharType*& _Next2,
    ) const;




    _State
    The conversion state that is maintained between calls to the member function.

    _First1
    Pointer to the beginning of the sequence to be converted.

    _Last1
    Pointer to the end of the sequence to be converted.

    _Next1
    Pointer beyond the end of the converted sequence, to the first unconverted character.

    _First2
    Pointer to the beginning of the converted sequence.

    _Last2
    Pointer to the end of the converted sequence.

    _Next2
    Pointer to the CharType that comes after the last converted CharType, to the first unaltered character in the destination sequence.


    Return Value
    A return that indicates the success, partial success, or failure of the operation. The function returns:

    codecvt_base::error if the source sequence is ill formed.
    codecvt_base::noconv if the function performs no conversion.
    codecvt_base::ok if the conversion succeeds.
    codecvt_base::partial if the source is insufficient or if the destination is not large enough, for the conversion to succeed.


    Так что 8 и 16 битными байтами дело не ограничивается.

    codecvt Class
    A template class that describes an object that can serve as a locale facet that is able to control conversions between a sequence of values used to encode characters within the program and a sequence of values used to encode characters outside the program.


    Понадобится — можно хоть из 24-битных CharType в 40-битные "байты" и наоборот конвертировать.
    А че тут Rakafon про строго 8-битные байты наговорил, забудь.
    Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
    Re[11]: тысяча третий раз про Юникод
    От: Rakafon Украина http://rakafon.blogspot.com/
    Дата: 15.10.09 13:07
    Оценка:
    Здравствуйте, pepsicoca, Вы писали:
    P>И что, внутри фасцета я могу рекурсивно вызвать повторное чтение, чтобы считать дополнительный байт и уложить его во вторую половину wchar_t?

    Да я просто говорю как стандартные потоковые классы себя ведут по умолчанию. Ничто вам не мешает написать свой фацет (наподобие, как здесь: Standard file streams and std::locale) и в функции do_in читать сразу 2 байта и помещать их соответственно в wchar_t, так же и наоборот в функции do_out из своей переменной wchar_t ложить в поток сразу два байта. Таким макаром можно хоть 16-ти байтовые символы иметь и читать и писать их за раз потоковым классом std::basic_ifstream<uint128>/std::basic_ofstream<uint128>. Просто для этого надо немного "ручками" изменить стандартное поведение потоковых классов.
    "Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
    Re[12]: тысяча третий раз про Юникод
    От: Rakafon Украина http://rakafon.blogspot.com/
    Дата: 15.10.09 13:10
    Оценка:
    Здравствуйте, Sergey, Вы писали:
    S>Понадобится — можно хоть из 24-битных CharType в 40-битные "байты" и наоборот конвертировать.
    S>А че тут Rakafon про строго 8-битные байты наговорил, забудь.

    Ха. Очень умно! Я говорю о стандартном поведении стандартных потоковых классов С++, а не о потоковых классах, обработанных напильником. Вот когда прилетят пришельцы, и вы получите таск заразить их бортовой писюк, в котором крутятся 40-битные байты, вируснёй, вот тогда и будете из 24-битных CharType в 40-битные "байты" и наоборот конвертировать.
    "Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
    Re[5]: тысяча третий раз про Юникод
    От: alsemm Россия  
    Дата: 15.10.09 13:33
    Оценка:
    Здравствуйте, pepsicoca, Вы писали:

    P>Здравствуйте, alsemm, Вы писали:


    A>>Здравствуйте, pepsicoca, Вы писали:


    P>>>Здравствуйте, K13, Вы писали:


    P>>>>>3. Если в экзешнике уже лежит Юникодная строка, почему кириллица не печатается без явного указания локали функцией imbue? Ведь по Юникоду однозначно определяется начертание символа. И чтобы напечатать Юникод локаль не нужна.


    K13>>>>потоки ввода-вывода работают с char. Без указания, какая именно кодировка является активной, не обойтись.


    P>>>Эта информация содержится в каждом коде Юникода. То есть по коду Юникода можно понять, какой это язык и слазить в систему за соответствующим начертанием символа в соответствующую таблицу.

    A>>Что это за таблица такая волшебная?

    P>Ну где там винда хранит начертание символов? В шрифтах наверное. Значит в шрифт.

    Ну и что ей делать, если в шрифте который выбран для консоли нет глифа соответ. юникодному символу?
    Re[6]: тысяча третий раз про Юникод
    От: pepsicoca  
    Дата: 15.10.09 14:00
    Оценка:
    Здравствуйте, alsemm, Вы писали:

    A>Здравствуйте, pepsicoca, Вы писали:


    P>>Здравствуйте, alsemm, Вы писали:


    A>>>Здравствуйте, pepsicoca, Вы писали:


    P>>>>Здравствуйте, K13, Вы писали:


    P>>>>>>3. Если в экзешнике уже лежит Юникодная строка, почему кириллица не печатается без явного указания локали функцией imbue? Ведь по Юникоду однозначно определяется начертание символа. И чтобы напечатать Юникод локаль не нужна.


    K13>>>>>потоки ввода-вывода работают с char. Без указания, какая именно кодировка является активной, не обойтись.


    P>>>>Эта информация содержится в каждом коде Юникода. То есть по коду Юникода можно понять, какой это язык и слазить в систему за соответствующим начертанием символа в соответствующую таблицу.

    A>>>Что это за таблица такая волшебная?

    P>>Ну где там винда хранит начертание символов? В шрифтах наверное. Значит в шрифт.

    A>Ну и что ей делать, если в шрифте который выбран для консоли нет глифа соответ. юникодному символу?

    На выбор:

    1. Ругнуться (вернуть ошибку потока).
    2. Поискать в другом шрифте.
    3. Пожаловаться в ЛСР.
    4. Предложить сменить шрифт консоли.
    5. Сменить шрифт консоли автоматически.
    6. Иметь шрифт консоли со всеми символами Юникода (не зря же винда занимает свои гигабайты на диске).
    7. Вывести знак вопроса на месте символа.

    Впрочем, все это не имеет отношения к обсуждаемому вопросу. Такие же проблемы со шрифтом возникают, если я сам подключаю локаль с помощью imbue (то есть вполне может не быть нужного шрифта в системе). Я только хочу, чтобы для широких потоков imbue делалось автоматически. Вся информация для того, чтобы по коду Юникодного символа определять кодировку в системе есть. Зачем для этого напрягать пользователя — непонятно.
    Re[13]: тысяча третий раз про Юникод
    От: Sergey Россия  
    Дата: 15.10.09 14:01
    Оценка:
    Здравствуйте, Rakafon, Вы писали:

    S>>Понадобится — можно хоть из 24-битных CharType в 40-битные "байты" и наоборот конвертировать.

    S>>А че тут Rakafon про строго 8-битные байты наговорил, забудь.

    R>Ха. Очень умно! Я говорю о стандартном поведении стандартных потоковых классов С++, а не о потоковых классах, обработанных напильником.


    Стандарт ничего не говорит о том, что конверсию из последовательности wchar_t в последовательность char надо делать так, будто с широкого конца у нас UTF-16 а с узкого — cp1251 или че там у юзера в винде задано. Лично я обычно предпочитаю такую конверсию, при которой половинки (или там четвертинки) wchar_t раскладываются по байтам тупо по порядку Как не трудно догадаться, при этом особой разницы между разными размерами "байт" в файлах нет.
    Ну и вызов imbue за доработку напильником я тоже не считаю.

    R>Вот когда прилетят пришельцы, и вы получите таск заразить их бортовой писюк, в котором крутятся 40-битные байты, вируснёй, вот тогда и будете из 24-битных CharType в 40-битные "байты" и наоборот конвертировать.


    Все ж знают — у пришельцев система счисления с основанием e, а вовсе не двоичная. Так что С++ тут не годицца.
    Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
    Re[7]: тысяча третий раз про Юникод
    От: Rakafon Украина http://rakafon.blogspot.com/
    Дата: 15.10.09 14:46
    Оценка: -1
    Здравствуйте, pepsicoca, Вы писали:
    P>Я только хочу, чтобы для широких потоков imbue делалось автоматически. Вся информация для того, чтобы по коду Юникодного символа определять кодировку в системе есть.

    Я как-то раз ехал домой с работы в маршрутке, и рядом сел молодой папаша с маленьким сыном в возрасте "почемучки". У них среди прочего состоялся такой разговор.

    — Папа, а почему трамваи ездят по рельсам, а не по дороге, как машины и автобусы? Я хочу чтобы трамваи ездили по дороге!!!
    — Понимаешь, трамвай очень тяжёлый, намного тяжелее автобуса или машины. Поэтому ему сделали железные колёса и построили по среди дороги рельсы, чтоб он мог ездить.
    — А я всё равно хочу чтобы трамвай ездил по дороге!
    — Ну в таком случае он своими колёсами поломал бы дорогу, и тогда не смогли бы ездить автобусы, маршрутки и машины.
    — Ну так пусть ему сделают резиновые колёса: я хочу чтобы трамвай ездил по дороге!!!

    ... и так далее ... помню папаша тогда запарился объяснять своему чаду, почему же всё-таки колёса у трамвая железные и ездит но по рельсам. Но надо отдать папаше должное: он терпеливо объяснял своему чаду всё, чтобы он ни спрашивал, говорил с ребёнком, а не послал его, как это бывает делают родители, которых задолбали их же дети.

    ... так вот ... к чему это я говорю: к тому, что мне ваше "Я хочу, чтобы imbue делалось автоматически" почему-то очень напоминает "я хочу чтобы трамвай ездил по дороге, а не по рельсам" ...

    "Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
    Re[8]: тысяча третий раз про Юникод
    От: pepsicoca  
    Дата: 15.10.09 15:17
    Оценка:
    Здравствуйте, Rakafon, Вы писали:

    R>... так вот ... к чему это я говорю: к тому, что мне ваше "Я хочу, чтобы imbue делалось автоматически" почему-то очень напоминает "я хочу чтобы трамвай ездил по дороге, а не по рельсам" ...


    R>


    А мне Ваше "Для Юникода надо делать imbue" напоминают "рыбе надо зонтик, она же в воде все время". Это же Юникод. Он для того и сделан, чтобы вручную локаль не переключать.
    Re[9]: тысяча третий раз про Юникод
    От: Rakafon Украина http://rakafon.blogspot.com/
    Дата: 15.10.09 15:34
    Оценка: -1
    Здравствуйте, pepsicoca, Вы писали:
    P>А мне Ваше "Для Юникода надо делать imbue" напоминают "рыбе надо зонтик, она же в воде все время". Это же Юникод. Он для того и сделан, чтобы вручную локаль не переключать.

    А я где-то говорил, что для Юникода надо делать imbue? До меня вообще как-то не совсем доходит фраза "Для Юникода надо делать imbue" ...
    imbue надо делать для С++ потокового класса std::wcout, вывод которого в консоль не имеет никакого отношения к юникоду. Почему это надо делать: здесь, а также в соседних идиентичных ветках, которые вы с лёгкой руки расплодили, вам как минимум три человека объяснили почему именно это надо делать, причём раза по два/три каждый.

    ...

    "Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
    Re[10]: тысяча третий раз про Юникод
    От: pepsicoca  
    Дата: 15.10.09 15:49
    Оценка: +1
    Здравствуйте, Rakafon, Вы писали:

    R>Здравствуйте, pepsicoca, Вы писали:

    P>>А мне Ваше "Для Юникода надо делать imbue" напоминают "рыбе надо зонтик, она же в воде все время". Это же Юникод. Он для того и сделан, чтобы вручную локаль не переключать.

    R>А я где-то говорил, что для Юникода надо делать imbue? До меня вообще как-то не совсем доходит фраза "Для Юникода надо делать imbue" ...

    R>imbue надо делать для С++ потокового класса std::wcout, вывод которого в консоль не имеет никакого отношения к юникоду. Почему это надо делать: здесь, а также в соседних идиентичных ветках, которые вы с лёгкой руки расплодили, вам как минимум три человека объяснили почему именно это надо делать, причём раза по два/три каждый.

    R>...


    R>


    Да тут не три, ту тридцать три человека отметились. Но максимум, что они сказали, это: "в виндах надо делать imbue для std::wcout потому, что так сейчас сделан поток std::wcout". А я Вам говорю — неправильно сейчас сделан поток std::wcout. Его можно и нужно сделать так, что при выводе Юникода не надо будет делать imbue. А то, как он сейчас сделан, это противоречит концепции Юникода.
    Re[11]: тысяча третий раз про Юникод
    От: andrey.desman  
    Дата: 15.10.09 16:06
    Оценка:
    Здравствуйте, pepsicoca, Вы писали:

    P>Да тут не три, ту тридцать три человека отметились. Но максимум, что они сказали, это: "в виндах надо делать imbue для std::wcout потому, что так сейчас сделан поток std::wcout". А я Вам говорю — неправильно сейчас сделан поток std::wcout. Его можно и нужно сделать так, что при выводе Юникода не надо будет делать imbue. А то, как он сейчас сделан, это противоречит концепции Юникода.


    Ну напиши письмо в микрософт, от нас то ты что хочешь?
    Re[12]: тысяча третий раз про Юникод
    От: pepsicoca  
    Дата: 15.10.09 16:15
    Оценка: -1
    Здравствуйте, andrey.desman, Вы писали:

    AD>Здравствуйте, pepsicoca, Вы писали:


    P>>Да тут не три, ту тридцать три человека отметились. Но максимум, что они сказали, это: "в виндах надо делать imbue для std::wcout потому, что так сейчас сделан поток std::wcout". А я Вам говорю — неправильно сейчас сделан поток std::wcout. Его можно и нужно сделать так, что при выводе Юникода не надо будет делать imbue. А то, как он сейчас сделан, это противоречит концепции Юникода.


    AD>Ну напиши письмо в микрософт, от нас то ты что хочешь?


    Это не в микрософт, это Страуструпу писать надо. Ну или Алексу Степанову накрайняк.
    Re[13]: тысяча третий раз про Юникод
    От: Sergey Россия  
    Дата: 15.10.09 16:48
    Оценка: +1 :)
    Здравствуйте, pepsicoca, Вы писали:

    P>>>Да тут не три, ту тридцать три человека отметились. Но максимум, что они сказали, это: "в виндах надо делать imbue для std::wcout потому, что так сейчас сделан поток std::wcout". А я Вам говорю — неправильно сейчас сделан поток std::wcout. Его можно и нужно сделать так, что при выводе Юникода не надо будет делать imbue. А то, как он сейчас сделан, это противоречит концепции Юникода.


    AD>>Ну напиши письмо в микрософт, от нас то ты что хочешь?


    P>Это не в микрософт, это Страуструпу писать надо. Ну или Алексу Степанову накрайняк.


    Ну тогда напиши в начале программы _setmode(_fileno(stdout), _O_U16TEXT); (требует хедеров io.h и fcntl.h) и еще раз подумай, кто тут виноват — мокрософт или Страуструп
    Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
    Re: тысяча третий раз про std streams
    От: c-smile Канада http://terrainformatica.com
    Дата: 15.10.09 18:23
    Оценка: :)
    Здравствуйте, pepsicoca, Вы писали:

    тысяча третий раз говорится что streams в C++ они имплементируют некий вселенский принцип, т.е. не для людей.

    Нарисуй себе такое вот:

    #include "stdafx.h"
    #include <stdlib.h>
    #include <windows.h>
    
    class console_stream
    {
    public:
      console_stream( unsigned t ): h(0) { h = GetStdHandle(t); }
      console_stream& operator << (const wchar_t* str) { write(str); return *this; }
      console_stream& operator << (int i) { wchar_t buf[64]; write(_itow(i,buf,10)); return *this; }
    private:
      void write(const wchar_t* str)
      {
        DWORD numchars;
        if(h) WriteConsoleW(h,str,wcslen(str),&numchars,0);
      }
      HANDLE h;
    };
    
    console_stream cin(STD_INPUT_HANDLE), cout(STD_OUTPUT_HANDLE), cerr(STD_ERROR_HANDLE);
    
    #pragma setlocale( "russian" )
    
    int main(int argc, char* argv[])
    {
      cout << L"Привет мир!\n";
        return 0;
    }


    и будет тебе хорошо.
    Re[2]: тысяча третий раз про std streams
    От: Sergey Россия  
    Дата: 15.10.09 18:28
    Оценка: 1 (1)
    Здравствуйте, c-smile, Вы писали:

    CS>Здравствуйте, pepsicoca, Вы писали:


    CS>тысяча третий раз говорится что streams в C++ они имплементируют некий вселенский принцип, т.е. не для людей.


    CS>Нарисуй себе такое вот:


    CS>
    CS>#include "stdafx.h"
    CS>#include <stdlib.h>
    CS>#include <windows.h>
    
    CS>class console_stream
    CS>{
    CS>public:
    CS>  console_stream( unsigned t ): h(0) { h = GetStdHandle(t); }
    CS>  console_stream& operator << (const wchar_t* str) { write(str); return *this; }
    CS>  console_stream& operator << (int i) { wchar_t buf[64]; write(_itow(i,buf,10)); return *this; }
    CS>private:
    CS>  void write(const wchar_t* str)
    CS>  {
    CS>    DWORD numchars;
    CS>    if(h) WriteConsoleW(h,str,wcslen(str),&numchars,0);
    CS>  }
    CS>  HANDLE h;
    CS>};
    
    CS>console_stream cin(STD_INPUT_HANDLE), cout(STD_OUTPUT_HANDLE), cerr(STD_ERROR_HANDLE);
    
    CS>#pragma setlocale( "russian" )
    
    CS>int main(int argc, char* argv[])
    CS>{
    CS>  cout << L"Привет мир!\n";
    CS>    return 0;
    CS>}
    CS>


    CS>и будет тебе хорошо.


    А че так сложно? Для VC достаточно


    #include <iostream>
    #include <io.h>
    #include <fcntl.h>
    
    int main(int argc, char* argv[])
    {
        _setmode(_fileno(stdout), _O_U16TEXT);
        std::wcout << L"Привет мир!";
        return 0;
    }
    Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
    Re[2]: тысяча третий раз про Юникод
    От: netch80 Украина http://netch80.dreamwidth.org/
    Дата: 16.10.09 08:07
    Оценка:
    Здравствуйте, K13, Вы писали:

    P>>Выяснилось, что в исходнике кирилическая строка L"привет" хранится в виде кода 1251 (0xef 0xf0 0xe8 0xe2 0xe5 0xf2).


    K13>it depends. Вот у нас за такой исходник можно получить по башке, потому что принято решение все исходники сохранять как UTF-8 без BOM.

    K13>Иначе возникают проблемы на маке :)

    Кстати, сейчас относительно популярен ещё такой метод, как описание кодировки в самом файле и интерпретация её одновременно редакторами и компиляторами. Вот, например, в документации Python:

    If a comment in the first or second line of the Python script matches the regular expression coding[=:]\s*([-\w.]+), this comment is processed as an encoding declaration; the first group of this expression names the encoding of the source code file. The recommended forms of this expression are

    # -*- coding: <encoding-name> -*-

    which is recognized also by GNU Emacs, and

    # vim:fileencoding=<encoding-name>

    which is recognized by Bram Moolenaar’s VIM. In addition, if the first bytes of the file are the UTF-8 byte-order mark ('\xef\xbb\xbf'), the declared file encoding is UTF-8 (this is supported, among others, by Microsoft’s notepad).

    If an encoding is declared, the encoding name must be recognized by Python. The encoding is used for all lexical analysis, in particular to find the end of a string, and to interpret the contents of Unicode literals. String literals are converted to Unicode for syntactical analysis, then converted back to their original encoding before interpretation starts. The encoding declaration must appear on a line of its own.


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

    По крайней мере первый вопрос треда это решает.

    P>>3. Если в экзешнике уже лежит Юникодная строка, почему кириллица не печатается без явного указания локали функцией imbue? Ведь по Юникоду однозначно определяется начертание символа. И чтобы напечатать Юникод локаль не нужна.

    K13>потоки ввода-вывода работают с char. Без указания, какая именно кодировка является активной, не обойтись.

    Насколько я понял, автору треда хотелось автоподхвата этой информации (в какой кодировке скорее всего будет работать такой поток) из активной локали. Это безусловно полезно — хотя бы потому, что не нужно будет пытаться эту информацию вычислять из локали (что может быть нетривиальным).

    K13>"Переключать на ходу" нельзя -- иначе при пайпе/записи в файл нам надо вставлять мета-символы между символами сообщения, а делать это мы не вправе.


    Я не понимаю, почему тут надо будет вставлять метасимволы. Метасимволы — это вопрос более высокого уровня протокола, если он есть (в соседнем по сравнению с Windows мире, на ANSI-style терминалах, можно переключать кодировки;)) Поток должен просто отработать директиву "с данного момента перекодирование должно идти в кодировку Z". Умеет он отобразить результат или нет — это уже следующий вопрос, но подобные установки обычно имеют дополнительный признак — что делать в случае невозможности перекодировки (игнорировать, выдавать фиксированный заместительный символ, возбуждать исключение...)
    The God is real, unless declared integer.
    Re[4]: тысяча третий раз про Юникод
    От: MasterZiv СССР  
    Дата: 16.10.09 20:39
    Оценка:
    IID пишет:

    > Консоль в винде уникодная. Но ты прав, бесполезно писать бред. Причём

    > неважно сколько раз.

    Она может и юникодная, в душе, потенциально. Но
    вот как её заставить понимать юникод — не понятно.
    Posted via RSDN NNTP Server 2.1 beta
    Re[5]: тысяча третий раз про Юникод
    От: Sergey Россия  
    Дата: 16.10.09 20:55
    Оценка:
    Здравствуйте, MasterZiv, Вы писали:

    >> Консоль в винде уникодная. Но ты прав, бесполезно писать бред. Причём

    >> неважно сколько раз.

    MZ>Она может и юникодная, в душе, потенциально. Но

    MZ>вот как её заставить понимать юникод — не понятно.

    Да все так же — mode con codepage select=65001
    И будет utf-8 консоль. Или что-то другое требуется?
    Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
    Re[6]: тысяча третий раз про Юникод
    От: MasterZiv СССР  
    Дата: 17.10.09 08:34
    Оценка:
    Sergey wrote:

    > Да все так же — mode con codepage select=65001

    > И будет utf-8 консоль. Или что-то другое требуется?

    Ну, требовалось -- то UCS-2.
    Posted via RSDN NNTP Server 2.1 beta
    Re[7]: тысяча третий раз про Юникод
    От: Sergey Россия  
    Дата: 17.10.09 09:18
    Оценка:
    Здравствуйте, MasterZiv, Вы писали:

    >> Да все так же — mode con codepage select=65001

    >> И будет utf-8 консоль. Или что-то другое требуется?

    MZ>Ну, требовалось -- то UCS-2.


    То, что требовалось, решается одной строчкой в начале программы — _setmode(_fileno(stdout), _O_U16TEXT); Потому что проблема там в том, что функция fputwc в зависимости от настроек для конкретного файла может взять да перевести широкие символы в узкие перед выводом. stdout один, и для wcout и для cout, если перевести его в "широкий" режим, то обычный cout работать перестанет. В общем похоже что пацаны, которые этот кусок CRT писали, просто не стали особо заморачиваться да и переложили проблемы по настройке вывода на пользователя. Хотя могли бы сделать все и по человечески, так чтобы UCS-2 с ANSI в одном файле уживались.
    Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.