тысяча третий раз про Юникод
От: 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 просто по-другому кодирует тот же Юникод. Так что проблемы композитов остаются.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.