Здравствуйте, pepsicoca, Вы писали:
P>Здравствуйте, Kh_Oleg, Вы писали:
K_O>>Здравствуйте, igna, Вы писали:
I>>>Здравствуйте, Kh_Oleg, Вы писали:
K_O>>>>Если указана русская locale, эти числа будут конвертированы в Unicode диапазон 0400h-04FFh, если мы, скажем, укажем японскую locale, то эти же числа из исходного текста будут конвертированы в другой диапазон кодов Unicode — 3040h-30FFh.
I>>>Ты не хочешь ли сказать, что выполняемое на этапе компиляции преобразование зависит от того, закоментирована ли std::wcout.imbue(std::locale("rus_rus.866"))?
K_O>>Мне кажется, что преобразование происходит не на этапе компиляции.
P>Скорее всего именно так. То есть wcout выводит коды, а imbue указывает, какую таблицу нужно брать.
P>Но тогда встают вопросы:
P>1. Где хранятся ВСЕ таблицы? В CRT? В экзешнике?
Некоторые таблицы храняться в CRT. Для тех кодировок, которые системе не известны таблиц нет
P>2. Очевидно, что если imbue это механизм времени исполнения, то хранится должны ВСЕ таблицы, а imbue только выбирает нужную. Не многовато-ли хранить ВСЕ таблицы в экзешнике?
В exe ничего не хранится, если только он с CRT не слинкован статически. Таблиц перекодировок ровно столько, сколько самих кодировок однобайтных — мильон питсот тыщь Из них штук 30, 40 самых распространенных забиты в CRT.
P>Для винды это 65тыщ кодов, все-таки обозримо.
Откуда цифра?
P>А для Юникса-то 4 млрд кодов(!).
Это неверно, http://en.wikipedia.org/wiki/Unicode:
the latest version of Unicode consists of a repertoire of more than 107,000 characters
...
Unicode defines a codespace of 1,114,112 code points in the range 0hex to 10FFFF
Т.е. всего под Unicode code points зарезервировано 1,114,112 элементов, но не все на сегодня заняты.
P>3. Как задать китайские строки, кодов в которых гораздо больше, чем 128 кодов из второй половины таблицы ASCII?
Google DBCS
Здравствуйте, Кодт, Вы писали:
К>Кардинальное лечение, кстати — это ::setlocale(LC_CTYPE, "") — т.е. установить юзерскую кодировку. Можно и явно указать "rus_rus.1251", и "rus_rus.866". К>Это повлияет не только на wcout, но и на wprintf.
Еще и на TranslateMessage, если цикл обработки сообщений писать руками.
Здравствуйте, alsemm, Вы писали:
A>Здравствуйте, pepsicoca, Вы писали:
P>>Если закомментировать строчку std::wcout.imbue(std::locale("rus_rus.866"));, то русский "привет" не печатается. A>Это от того, что все wZZZ функции из стандартных C/C++ библиотек это, грубо говоря, просто обертки над соответствующими функциями без префикса 'w', соответсвенно зависят от локали.
A>Отказаться от локали невозможно, т.к., например вывод A>
A>printf('%f\n', 3.14);
A>
A>будет зависеть от локали (разделитель — точка или запятая). A>Зачем указывать локаль при выводе на консоль? — чтобы дать хинт системе какие шрифты использовать для отображения символов. Ведь обычно шрифты делаются для определенного подмножества Unicode code point-ов.
Выяснилось, что кирилические строки хранятся в виндовском экзешнике в Юникоде. То есть хинт системе, какая это именно локаль давать не надо. система может сама понять, что это кирилица, по номеру страницы Юникода. Это должно работать даже в худшем случае неюникодного терминала. Почему система не может определить по коду Юникода локаль и сама сделать imbue соответствующей локали?
A>Для полноценной работы с Unicode текстом средств стандартных C/C++ библиотек недостаточно, нужно использовать спец. библиотеки, ICU, например. Например tolower/toupper — locale specific, так что если вы получили произвольную unicode строку, tolower/toupper в общем случае к ней применять нельзя. А в ICU есть соответ. функции, которые от локали не зависят.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Kh_Oleg, Вы писали:
K_O>>А вот почему stream не может отображать такие строки без явного задания locale — это уже отдельный вопрос, какие-то их внутренние заморочки.
К>Всё очень просто, на самом деле. Ну, почти просто.
К>1. Консольный вывод — (мульти)байтовый, а не вайдовый. Поэтому wcout должен выполнять преобразование wctomb.
Чтобы выполнить преобразование wctomb не надо знать локаль. Вернее, не надо явно указывать локаль. То, что в данный момент пойдет на вывод кириллица можно понять из кода Юникода.
#include <stdio.h>
#include <iostream>
#include <locale>
using namespace std;
wchar_t const* hello = L"Hello/Привет"; // документ был в кодировке 1251, компилятор правильно прочитал текстvoid testp()
{
wprintf(L"wprintf: %s\n", hello);
}
void testc()
{
wcout << L"wcout: " << hello << endl;
if(!wcout) wcout.clear(), wcout << L"error" << endl;
}
void test()
{
testp(); testc();
}
void imbu(char const* t)
{
locale l(t);
wcout.imbue(l);
cout << "imbue " << t << " = " << l.name() << endl;
testc();
printf("\n");
}
void setl(char const* t)
{
char const* l = ::setlocale(LC_CTYPE, t);
printf("setlocale : %s = %s\n", t, l ? l : "<null>");
test();
printf("\n");
}
int main()
{
test();
//wprintf: Hello/?????? - проверили исходную ситуацию: всё плохо!
//wcout: Hello/error
setl("");
//setlocale : = Russian_Russia.1251
//wprintf: Hello/Привет - как ни странно, даже 1251 прекрасно превратилось в 866 (средствами CRT)
//wcout: Hello/Привет - заметьте: imbue не понадобилось
setl("C");
//setlocale : C = C
//wprintf: Hello/?????? - вернулись к исходной ситуации
//wcout: Hello/error
setl("rus_rus.866");
//setlocale : rus_rus.866 = Russian_Russia.866
wprintf: Hello/Привет
wcout: Hello/Привет
imbu("");
//imbue = Russian_Russia.1251
//wcout: Hello/¦ЁштхЄ - wcout и CRT вошли в противоречие и совместно наколбасили
imbu("C");
//imbue C = C
//wcout: Hello/error - wcout самостоятельно попытался сконвертировать и обломился, встретив не-ASCII
imbu("rus_rus.866");
//imbue rus_rus.866 = Russian_Russia.866
//wcout: Hello/Привет
setl("C");
//setlocale : C = C
//wprintf: Hello/??????
//wcout: Hello/Привет - wcout обошёлся своей локалью, не прибегая к помощи глобальной (которая Си) - и обломился
imbu("");
//imbue = Russian_Russia.1251
//wcout: Hello/¦ЁштхЄ - опять попутались
imbu("C");
//imbue C = C
//wcout: Hello/error - обе локали - глобальная и wcout-ская - Си
imbu("rus_rus.866");
//imbue rus_rus.866 = Russian_Russia.866
//wcout: Hello/Привет
}
А если вывести в файл, то увидим, что кодировки смешались. Некоторые приветы заменились крякозябрами.
Причём "type t.txt" (встроенная команда) и "cat t.txt" (у меня стоит цигвин) дадут разный результат
Здравствуйте, pepsicoca, Вы писали:
P>Здравствуйте, alsemm, Вы писали:
A>>Здравствуйте, pepsicoca, Вы писали:
P>>>Если закомментировать строчку std::wcout.imbue(std::locale("rus_rus.866"));, то русский "привет" не печатается. A>>Это от того, что все wZZZ функции из стандартных C/C++ библиотек это, грубо говоря, просто обертки над соответствующими функциями без префикса 'w', соответсвенно зависят от локали.
A>>Отказаться от локали невозможно, т.к., например вывод A>>
A>>printf('%f\n', 3.14);
A>>
A>>будет зависеть от локали (разделитель — точка или запятая). A>>Зачем указывать локаль при выводе на консоль? — чтобы дать хинт системе какие шрифты использовать для отображения символов. Ведь обычно шрифты делаются для определенного подмножества Unicode code point-ов.
P>Выяснилось, что кирилические строки хранятся в виндовском экзешнике в Юникоде. То есть хинт системе, какая это именно локаль давать не надо. система может сама понять, что это кирилица, по номеру страницы Юникода.
Что такое "номер страницы Юникода"?
P>Это должно работать даже в худшем случае неюникодного терминала. Почему система не может определить по коду Юникода локаль и сама сделать imbue соответствующей локали?
Потому что один и тот же символ Юникода может быть представлен в разных кодироваках (aka локали) по разному. Например буква 'ю' в cp1251 — 254, а в KOI8-R — 192.
Здравствуйте, alsemm, Вы писали:
A>Для полноценной работы с Unicode текстом средств стандартных C/C++ библиотек недостаточно, нужно использовать спец. библиотеки, ICU, например. Например tolower/toupper — locale specific, так что если вы получили произвольную unicode строку, tolower/toupper в общем случае к ней применять нельзя. А в ICU есть соответ. функции, которые от локали не зависят.
Эээ, а как эти функции с турецкой i поступают? Откуда догадываются что она турецкая?
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, Sergey, Вы писали:
S>Здравствуйте, alsemm, Вы писали:
A>>Для полноценной работы с Unicode текстом средств стандартных C/C++ библиотек недостаточно, нужно использовать спец. библиотеки, ICU, например. Например tolower/toupper — locale specific, так что если вы получили произвольную unicode строку, tolower/toupper в общем случае к ней применять нельзя. А в ICU есть соответ. функции, которые от локали не зависят.
S>Эээ, а как эти функции с турецкой i поступают? Откуда догадываются что она турецкая? http://en.wikipedia.org/wiki/Turkish_dotted_and_dotless_I#In_computing
Здравствуйте, pepsicoca, Вы писали:
К>>1. Консольный вывод — (мульти)байтовый, а не вайдовый. Поэтому wcout должен выполнять преобразование wctomb. P>Чтобы выполнить преобразование wctomb не надо знать локаль. Вернее, не надо явно указывать локаль. То, что в данный момент пойдет на вывод кириллица можно понять из кода Юникода.
Нет. Нужно знать локаль выходного файлового потока. Он-то байтовый.
Потому что (w)printf и (w)cout пишут не прямо на экран!!!
Здравствуйте, alsemm, Вы писали:
S>>Здравствуйте, alsemm, Вы писали:
A>>>Для полноценной работы с Unicode текстом средств стандартных C/C++ библиотек недостаточно, нужно использовать спец. библиотеки, ICU, например. Например tolower/toupper — locale specific, так что если вы получили произвольную unicode строку, tolower/toupper в общем случае к ней применять нельзя. А в ICU есть соответ. функции, которые от локали не зависят.
S>>Эээ, а как эти функции с турецкой i поступают? Откуда догадываются что она турецкая? A>http://en.wikipedia.org/wiki/Turkish_dotted_and_dotless_I#In_computing
Не увидел там ответа на мой вопрос.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, alsemm, Вы писали:
A>Здравствуйте, pepsicoca, Вы писали:
P>>Здравствуйте, alsemm, Вы писали:
A>>>Здравствуйте, pepsicoca, Вы писали:
P>>>>Если закомментировать строчку std::wcout.imbue(std::locale("rus_rus.866"));, то русский "привет" не печатается. A>>>Это от того, что все wZZZ функции из стандартных C/C++ библиотек это, грубо говоря, просто обертки над соответствующими функциями без префикса 'w', соответсвенно зависят от локали.
A>>>Отказаться от локали невозможно, т.к., например вывод A>>>
A>>>printf('%f\n', 3.14);
A>>>
A>>>будет зависеть от локали (разделитель — точка или запятая). A>>>Зачем указывать локаль при выводе на консоль? — чтобы дать хинт системе какие шрифты использовать для отображения символов. Ведь обычно шрифты делаются для определенного подмножества Unicode code point-ов.
P>>Выяснилось, что кирилические строки хранятся в виндовском экзешнике в Юникоде. То есть хинт системе, какая это именно локаль давать не надо. система может сама понять, что это кирилица, по номеру страницы Юникода. A>Что такое "номер страницы Юникода"?
По старшему байту в 16-разрядном коде.
P>>Это должно работать даже в худшем случае неюникодного терминала. Почему система не может определить по коду Юникода локаль и сама сделать imbue соответствующей локали? A>Потому что один и тот же символ Юникода может быть представлен в разных кодироваках (aka локали) по разному. Например буква 'ю' в cp1251 — 254, а в KOI8-R — 192.
???
Для того и Юникод ввели, чтобы о локали забыть. Главное, что буква "ю" в Юникоде однозначно представляется. Получив Юникодный символ "ю" система может (и должна) сама понять, что это кириллица, слазить за начертанием буквы "ю" в таблицу кириллических шрифтов и напечатать букву "ю".
Здравствуйте, pepsicoca, Вы писали:
P>Здравствуйте, alsemm, Вы писали:
A>>Здравствуйте, pepsicoca, Вы писали:
P>>>Здравствуйте, alsemm, Вы писали:
A>>>>Здравствуйте, pepsicoca, Вы писали:
P>>>>>Если закомментировать строчку std::wcout.imbue(std::locale("rus_rus.866"));, то русский "привет" не печатается. A>>>>Это от того, что все wZZZ функции из стандартных C/C++ библиотек это, грубо говоря, просто обертки над соответствующими функциями без префикса 'w', соответсвенно зависят от локали.
A>>>>Отказаться от локали невозможно, т.к., например вывод A>>>>
A>>>>printf('%f\n', 3.14);
A>>>>
A>>>>будет зависеть от локали (разделитель — точка или запятая). A>>>>Зачем указывать локаль при выводе на консоль? — чтобы дать хинт системе какие шрифты использовать для отображения символов. Ведь обычно шрифты делаются для определенного подмножества Unicode code point-ов.
P>>>Выяснилось, что кирилические строки хранятся в виндовском экзешнике в Юникоде. То есть хинт системе, какая это именно локаль давать не надо. система может сама понять, что это кирилица, по номеру страницы Юникода. A>>Что такое "номер страницы Юникода"?
P>По старшему байту в 16-разрядном коде.
Чепуха какая-то. Рекомендую прочитать http://en.wikipedia.org/wiki/Unicode до полного осмысления.
P>>>Это должно работать даже в худшем случае неюникодного терминала. Почему система не может определить по коду Юникода локаль и сама сделать imbue соответствующей локали? A>>Потому что один и тот же символ Юникода может быть представлен в разных кодироваках (aka локали) по разному. Например буква 'ю' в cp1251 — 254, а в KOI8-R — 192.
P>???
Похоже кодировки и локали смешались просто в одну кашу, вот уже ничего и не понять
P>Для того и Юникод ввели, чтобы о локали забыть.
Не о локали, а о разных не UTF кодировках. Локаль и кодировка — это не синонимы. Я вот и сам запутался c этими понятиями в предыдущем своем посте в этой ветке
P>Главное, что буква "ю" в Юникоде однозначно представляется. Получив Юникодный символ "ю" система может (и должна) сама понять, что это кириллица, слазить за начертанием буквы "ю" в таблицу кириллических шрифтов и напечатать букву "ю".
Она конечно может, но ничего никому не должна. Я думаю, что консоль кочует из одной версии винды в другую без особых изменения со дня своего рождения. Если сильно достает, то напиши свой заменитель консоли который будет уметь делать все что ты описал. Может M$ его у тебя купит, если хорошо получится.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, pepsicoca, Вы писали:
К>>>1. Консольный вывод — (мульти)байтовый, а не вайдовый. Поэтому wcout должен выполнять преобразование wctomb. P>>Чтобы выполнить преобразование wctomb не надо знать локаль. Вернее, не надо явно указывать локаль. То, что в данный момент пойдет на вывод кириллица можно понять из кода Юникода.
К>Нет. Нужно знать локаль выходного файлового потока. Он-то байтовый. К>Потому что (w)printf и (w)cout пишут не прямо на экран!!!
Нет. Не нужно знать локаль выходного файлового потока. Его локаль нужно переключить в соответствии с той локалью, которая указана в коде Юникода. То есть по коду Юникода система сама может (и должна) делать imbue соответствующей локали. Тогда из байтового выходного потока мы получим юникодный выходной поток. Каким, собственно, и должен быть поток с именем wcout. А байтовым должен быть (и есть) поток cout. Вот в потоке cout переключение локалей более чем оправдано. А в потоке wcout переключать локали это все равно, что рыбе зонтик.
Здравствуйте, Sergey, Вы писали:
S>Здравствуйте, alsemm, Вы писали:
S>>>Здравствуйте, alsemm, Вы писали:
A>>>>Для полноценной работы с Unicode текстом средств стандартных C/C++ библиотек недостаточно, нужно использовать спец. библиотеки, ICU, например. Например tolower/toupper — locale specific, так что если вы получили произвольную unicode строку, tolower/toupper в общем случае к ней применять нельзя. А в ICU есть соответ. функции, которые от локали не зависят.
S>>>Эээ, а как эти функции с турецкой i поступают? Откуда догадываются что она турецкая? A>>http://en.wikipedia.org/wiki/Turkish_dotted_and_dotless_I#In_computing
S>Не увидел там ответа на мой вопрос.
Там общий принцип описан во втором абзаце.
В ICU есть два комплекта функций tolower/toupper:
/**
* The given character is mapped to its lowercase equivalent according to
* UnicodeData.txt; if the character has no lowercase equivalent, the character
* itself is returned.
*
* Same as java.lang.Character.toLowerCase().
*
* This function only returns the simple, single-code point case mapping.
* Full case mappings should be used whenever possible because they produce
* better results by working on whole strings.
* They take into account the string context and the language and can map
* to a result string with a different length as appropriate.
* Full case mappings are applied by the string case mapping functions,
* see ustring.h and the UnicodeString class.
* See also the User Guide chapter on C/POSIX migration:
* http://icu-project.org/userguide/posix.html#case_mappings
*
* @param c the code point to be mapped
* @return the Simple_Lowercase_Mapping of the code point, if any;
* otherwise the code point itself.
* @stable ICU 2.0
*/
U_STABLE UChar32 U_EXPORT2
u_tolower(UChar32 c);
/**
* Lowercase the characters in a string.
* Casing is locale-dependent and context-sensitive.
* The result may be longer or shorter than the original.
* The source string and the destination buffer are allowed to overlap.
*
* @param dest A buffer for the result string. The result will be zero-terminated if
* the buffer is large enough.
* @param destCapacity The size of the buffer (number of UChars). If it is 0, then
* dest may be NULL and the function will only return the length of the result
* without writing any of the result string.
* @param src The original string
* @param srcLength The length of the original string. If -1, then src must be zero-terminated.
* @param locale The locale to consider, or "" for the root locale or NULL for the default locale.
* @param pErrorCode Must be a valid pointer to an error code value,
* which must not indicate a failure before the function call.
* @return The length of the result string. It may be greater than destCapacity. In that case,
* only some of the result was written to the destination buffer.
* @stable ICU 2.0
*/
U_STABLE int32_t U_EXPORT2
u_strToLower(UChar *dest, int32_t destCapacity,
const UChar *src, int32_t srcLength,
const char *locale,
UErrorCode *pErrorCode);
Если во вторую скормить имя турецкой локали, наверное она сделает то, что требуется от нее с турецой i.
Здравствуйте, pepsicoca, Вы писали:
P>Нет. Не нужно знать локаль выходного файлового потока. Его локаль нужно переключить в соответствии с той локалью, которая указана в коде Юникода. То есть по коду Юникода система сама может (и должна) делать imbue соответствующей локали. Тогда из байтового выходного потока мы получим юникодный выходной поток. Каким, собственно, и должен быть поток с именем wcout. А байтовым должен быть (и есть) поток cout. Вот в потоке cout переключение локалей более чем оправдано. А в потоке wcout переключать локали это все равно, что рыбе зонтик.
Ну-ну. hello.exe>hello.txt — угадай, в какой кодировке будет выходной файл?
Впрочем, CRT может обнаружить, что в данный момент программа осуществляет ввод-вывод на консоль, и творчески подойти к выводу.
Вместо WriteFile(hStdOut,char_string,num_of_chars) использовать WriteConsole(hStdOut,wchar_string,num_of_wchars).
Здравствуйте, alsemm, Вы писали:
A>>>>>Для полноценной работы с Unicode текстом средств стандартных C/C++ библиотек недостаточно, нужно использовать спец. библиотеки, ICU, например. Например tolower/toupper — locale specific, так что если вы получили произвольную unicode строку, tolower/toupper в общем случае к ней применять нельзя. А в ICU есть соответ. функции, которые от локали не зависят.
S>>>>Эээ, а как эти функции с турецкой i поступают? Откуда догадываются что она турецкая? A>>>http://en.wikipedia.org/wiki/Turkish_dotted_and_dotless_I#In_computing
S>>Не увидел там ответа на мой вопрос. A>Там общий принцип описан во втором абзаце.
Ну то есть без локали оно работает неправильно?
A>В ICU есть два комплекта функций tolower/toupper:
...один комплект простой и работает неправильно, а второй — как в CRT
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, pepsicoca, Вы писали:
P>>Нет. Не нужно знать локаль выходного файлового потока. Его локаль нужно переключить в соответствии с той локалью, которая указана в коде Юникода. То есть по коду Юникода система сама может (и должна) делать imbue соответствующей локали. Тогда из байтового выходного потока мы получим юникодный выходной поток. Каким, собственно, и должен быть поток с именем wcout. А байтовым должен быть (и есть) поток cout. Вот в потоке cout переключение локалей более чем оправдано. А в потоке wcout переключать локали это все равно, что рыбе зонтик.
К>Ну-ну. hello.exe>hello.txt — угадай, в какой кодировке будет выходной файл?
Что имеется ввиду? Переназначение вывода средствами ОС в стиле Юникса? Если имеется ввиду это, то кодировка выходного файла зависит от того, что выдает hello.exe и куда перенаправляется вывод стрелкой. Если hello.exe выдает байтовый код и стрелкой перенаправляется в cout, то все будет нормально. Соответственно, есть 4 варианта только 2 из которых будут работать как надо. Впрочем, вполне можно представить себе перенаправление в wcout средствами ОС. Например
hello.exe=>hello.txt. Или еще как-то.
К>Впрочем, CRT может обнаружить, что в данный момент программа осуществляет ввод-вывод на консоль, и творчески подойти к выводу. К>Вместо WriteFile(hStdOut,char_string,num_of_chars) использовать WriteConsole(hStdOut,wchar_string,num_of_wchars).
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, alsemm, Вы писали:
A>>В ICU есть два комплекта функций tolower/toupper:
К>Но с немецким эсцетом ни одна из них не справится (наверно?)
Это когда, например, буква 'A' с кружком наверху представляется двумя символами? Думаю ICU-ые фнкции, которые конвертируют строки целиком, а не отдельные символы справятся.
Здравствуйте, Sergey, Вы писали:
S>...один комплект простой и работает неправильно, а второй — как в CRT
CRT-ая tolower конвертирует символ, а не строку. Так что всякие извращенные случаи, когда один заглавный символ превращается в несколько/0 прописных она обработать корректно не может.
Аргумент CRT-ой tolower — символ юникода, но он обязательно должен быть из текущей локали http://opengroup.org/onlinepubs/007908799/xsh/towlower.html:
The towlower() function has as a domain a type wint_t, the value of which must be a character representable as a wchar_t, and must be a wide-character code corresponding to a valid character in the current locale or the value of WEOF
Из этого следует, что если нужно конвертировать произвольную unicode строку, то перед вызовом towlower() для каждого символа строки надо определить какой он принадлежит локали (CRT для этого средств не предоставляет) и переключиться, если нужно. Однако, если даже правильно переключать локали результат будет не всегда корректным, т.к. towlower() не учитвает контекст символа.
Да, чуть не забыл, в случае, если sizeof(wchar_t) = 2 и кодировка не UCS2, а UTF16, т.е. надо иметь дело с surrogate pairs — towlower() вообще бесполезен.
И что такое CRT-ая towlower(), если не УГ после этого?