Re[9]: тысяча второй раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 10:08
Оценка: 6 (2)
Демонстрашилка
#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" (у меня стоит цигвин) дадут разный результат
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[2]: тысяча второй раз про Юникод
От: quodum  
Дата: 13.10.09 15:30
Оценка: :))
Здравствуйте, pepsicoca, Вы писали:

P>Модифицировал пример и самостоятельно сформировал Юникодную строку L"привет" в виде массива.


[]

P>Этот пример НЕ печатает русский "привет".


Этот пример печатает русский "привет":
#include <iostream>

wchar_t array[]={0x043f,0x0440,0x0438,0x0432,0x0435,0x0442,0};

int wmain(int argc, wchar_t* argv[])
{
    std::wcout.imbue(std::locale("rus_rus.866"));
    std::wcout<<L"hello"<<std::endl;
    std::wcout<<array<<std::endl;
    return 0;
}


Этот пример печатает русский "привет":
#include <iostream>

#pragma setlocale( "rus_rus.1251" )

int wmain(int argc, wchar_t* argv[])
{
    std::wcout.imbue(std::locale("rus_rus.866"));
    std::wcout<<L"hello"<<std::endl;
    std::wcout<<L"Привет"<<std::endl;
    return 0;
}



P>Очевидно, что std::wcout действительно работает все-таки не с Юникодом,

Очевидно, что внимательнее надо быть.

P>2. А честный Юникодный исходник бывает?

Бывает. Создайте уникодный файл Блокнотом и подсуньте его Студии.

P>Спасибо.

Удачи.
Re[8]: тысяча второй раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 09:37
Оценка: 3 (1)
Здравствуйте, Kh_Oleg, Вы писали:

K_O>А вот почему stream не может отображать такие строки без явного задания locale — это уже отдельный вопрос, какие-то их внутренние заморочки.


Всё очень просто, на самом деле. Ну, почти просто.

1. Консольный вывод — (мульти)байтовый, а не вайдовый. Поэтому wcout должен выполнять преобразование wctomb.

2. По умолчанию окно консоли работает в кодировке "OEM" — 866 (Cyrillic DOS), 860 (Western DOS) и т.п. Это влияет на то, как она переводит байты, вылетающие из stdout программы, в отображаемые глифы шрифта. Надо заметить, что консоль способна поддерживать юникод (лишь бы шрифт его поддерживал). Но wcout на это непосредственно влиять не может, так же как на заголовок или размер консоли — для этого существует Console API (а что существует в *nix — не ведаю).

3. А вот теперь самое главное. Смотрим пункт 1. По умолчанию локаль программы — отнюдь не юзерская или системная, а "C".
Вот фигня-то и получилась.

Кардинальное лечение, кстати — это ::setlocale(LC_CTYPE, "") — т.е. установить юзерскую кодировку. Можно и явно указать "rus_rus.1251", и "rus_rus.866".
Это повлияет не только на wcout, но и на wprintf.
Другие фасеты можно оставить сишными — иначе получите внезапные артефакты в виде десятичной запятой вместо точки, и т.п.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
тысяча второй раз про Юникод
От: pepsicoca  
Дата: 13.10.09 13:28
Оценка:
Добрый день.

Спрошу еще раз, потому что в старой ветке никто не читает.

Есть MSVC2003 и есть код.


// example.cpp : Defines the entry point for the console application.
//

#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;
}


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

Вот это мне как раз и непонятно. На то и Юникод, чтобы забыть о переключении таблиц символов. Если есть Юникодная строка, зачем мне указывать локаль для потока? Код Юникодного символа ОДНОЗНАЧНО определяет его начертание и принадлежность к тому или иному алфавиту. Зачем еще указывать локаль? Если текущий код это китайский иероглиф — пусть система напечатает китайский иероглиф. Если текущий код это греческая буква "кси" — пусть система напечатает греческую букву "кси". При чем тут локаль — совершенно непонятно. По моим понятиям, когда компилятор встречает в исходнике строку

L"привет"


он должен в объектнике создать Юникодную строку с русскими буквами. А дальше работать с Юникодом без указания на локаль.

Спасибо.
Re: тысяча второй раз про Юникод
От: Сергей Мухин Россия  
Дата: 13.10.09 13:38
Оценка:
Здравствуйте, pepsicoca, Вы писали:

P>
P>L"привет"
P>


P>он должен в объектнике создать Юникодную строку с русскими буквами. А дальше работать с Юникодом без указания на локаль.


Откуда компилятор знает, что они русские?

#pragma setlocale( "[locale-string]" )
---
С уважением,
Сергей Мухин
Re[2]: тысяча второй раз про Юникод
От: pepsicoca  
Дата: 13.10.09 13:47
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

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


P>>он должен в объектнике создать Юникодную строку с русскими буквами. А дальше работать с Юникодом без указания на локаль.


СМ>Откуда компилятор знает, что они русские?


СМ>#pragma setlocale( "[locale-string]" )


Очевидно, от редактора? В любом случае imbue это механизм времени исполнения, а к этому времени Юникодная строка

P>>
P>>L"привет"
P>>


Должна уже лежать в экзешнике.

Кстати, попробовал пример по указанной ссылке.

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

Оба варианта не работают.
Re[2]: тысяча второй раз про Юникод
От: igna Россия  
Дата: 13.10.09 13:48
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>Откуда компилятор знает, что они русские?


Ну когда спрашивающий раскомментирует (в смысле раскомментировывает ) std::wcout.imbue(std::locale("rus_rus.866")), то "привет" по-видимому печатается, так что проблема не в том, что компилятор не знает, руские там буквы или нет.
Re[3]: тысяча второй раз про Юникод
От: pepsicoca  
Дата: 13.10.09 14:05
Оценка:
СМ>>Откуда компилятор знает, что они русские?

СМ>>#pragma setlocale( "[locale-string]" )


P>Очевидно, от редактора? В любом случае imbue это механизм времени исполнения, а к этому времени Юникодная строка


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

Вопрос:

1. Умеет ли редактор и транслятор MSVC работать в Юникодными исходниками? Если да, то где этот режим включается?

Спасибо
Re[3]: тысяча второй раз про Юникод
От: Kh_Oleg  
Дата: 13.10.09 14:12
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, Сергей Мухин, Вы писали:


СМ>>Откуда компилятор знает, что они русские?


I>Ну когда спрашивающий раскомментирует (в смысле раскомментировывает ) std::wcout.imbue(std::locale("rus_rus.866")), то "привет" по-видимому печатается, так что проблема не в том, что компилятор не знает, русcкие там буквы или нет.


Именно, что не знает. Смотрите: первые 128 символов в ASCII и Unicode совпадают — поэтому латинские буквы печатаютcя.
Слово "привет" в исходном файле на С++, представляет собой некоторую последовательность чисел из диапазона выше 128. Так устроен формат ASCII, в котором сохраняется С++ исходник. Просто последовательность чисел. При компиляции компилятор читает этот файл (не имея при этом связи с редактором) и в зависимости от того, к какой locale мы хотим отнести данную последовательность кодов, он определяет диапазон кодов unicode, в которые следует произвести конвертацию. Если указана русская locale, эти числа будут конвертированы в Unicode диапазон 0400h-04FFh, если мы, скажем, укажем японскую locale, то эти же числа из исходного текста будут конвертированы в другой диапазон кодов Unicode — 3040h-30FFh. И, соответственно, отображаться на экране такая строка будет по-разному, в зависимости от locale.

Вот как-то так.
Re[4]: тысяча второй раз про Юникод
От: igna Россия  
Дата: 13.10.09 14:21
Оценка:
Здравствуйте, Kh_Oleg, Вы писали:

K_O>Если указана русская locale, эти числа будут конвертированы в Unicode диапазон 0400h-04FFh, если мы, скажем, укажем японскую locale, то эти же числа из исходного текста будут конвертированы в другой диапазон кодов Unicode — 3040h-30FFh.


Ты не хочешь ли сказать, что выполняемое на этапе компиляции преобразование зависит от того, закоментирована ли std::wcout.imbue(std::locale("rus_rus.866"))?
Re: тысяча второй раз про Юникод
От: pepsicoca  
Дата: 13.10.09 14:24
Оценка:
Здравствуйте, pepsicoca, Вы писали:

Модифицировал пример и самостоятельно сформировал Юникодную строку L"привет" в виде массива.

// example.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

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

wchar_t array[]={0x043f,0x0440,0x0438,0x0432,0x0435,0x0442,0};

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;
    std::wcout<<array<<std::endl;
    return 0;
}


где

wchar_t array[]={0x043f,0x0440,0x0438,0x0432,0x0435,0x0442,0};


Это юникодный русский L"привет", написанный мной в кодах и с нулем на конце.

Этот пример НЕ печатает русский "привет".

Очевидно, что std::wcout действительно работает все-таки не с Юникодом, а с локалью+код смещения из второй половины таблицы. Но при этом появляются новые вопросы:

Вопросы:

1. Для китайского языка смещение гораздо больше, чем 128 символов из второй половины ASCII-таблицы. Как же в ASCIIшном исходнике задать китайскую строку, хотя бы и с помощью китайской локали?

2. А честный Юникодный исходник бывает? И как тогда работает std::wcout? Или у честного Юникодного исходника и реализация библиотеки std::wcout другая и эта другая реализация библиотеки тоже честно работает с Юникодом, а не с локалью?

Спасибо.
Re[5]: тысяча второй раз про Юникод
От: Kh_Oleg  
Дата: 13.10.09 14:28
Оценка:
Здравствуйте, igna, Вы писали:

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


K_O>>Если указана русская locale, эти числа будут конвертированы в Unicode диапазон 0400h-04FFh, если мы, скажем, укажем японскую locale, то эти же числа из исходного текста будут конвертированы в другой диапазон кодов Unicode — 3040h-30FFh.


I>Ты не хочешь ли сказать, что выполняемое на этапе компиляции преобразование зависит от того, закоментирована ли std::wcout.imbue(std::locale("rus_rus.866"))?


Мне кажется, что преобразование происходит не на этапе компиляции.
Re[6]: тысяча второй раз про Юникод
От: igna Россия  
Дата: 13.10.09 14:36
Оценка:
Здравствуйте, Kh_Oleg, Вы писали:

K_O>Мне кажется, что преобразование происходит не на этапе компиляции.


Да? А в исполняемом файле его L"привет" как хранится? Прямо так как написано, безо всякого преобразования в коды?
Re[6]: тысяча второй раз про Юникод
От: pepsicoca  
Дата: 13.10.09 14:38
Оценка:
Здравствуйте, 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>Мне кажется, что преобразование происходит не на этапе компиляции.


Скорее всего именно так. То есть wcout выводит коды, а imbue указывает, какую таблицу нужно брать.

Но тогда встают вопросы:

1. Где хранятся ВСЕ таблицы? В CRT? В экзешнике?

2. Очевидно, что если imbue это механизм времени исполнения, то хранится должны ВСЕ таблицы, а imbue только выбирает нужную. Не многовато-ли хранить ВСЕ таблицы в экзешнике? Для винды это 65тыщ кодов, все-таки обозримо. А для Юникса-то 4 млрд кодов(!).

3. Как задать китайские строки, кодов в которых гораздо больше, чем 128 кодов из второй половины таблицы ASCII?
Re[7]: тысяча второй раз про Юникод
От: Kh_Oleg  
Дата: 13.10.09 15:01
Оценка:
Здравствуйте, igna, Вы писали:

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


K_O>>Мне кажется, что преобразование происходит не на этапе компиляции.


I>Да? А в исполняемом файле его L"привет" как хранится? Прямо так как написано, безо всякого преобразования в коды?

Как оказалось, в исполняемом файле хранится правильная Unicode строка. Очевидно, компилятор использует текущий locale, используемый в OC.
А вот почему stream не может отображать такие строки без явного задания locale — это уже отдельный вопрос, какие-то их внутренние заморочки.

Кстати, а какой locale установлен в ОС топикстартера? Если английский/американский — тогда можно объяснить такое поведение, если русский — тогда не знаю.
Re[8]: тысяча второй раз про Юникод
От: pepsicoca  
Дата: 13.10.09 15:26
Оценка:
Здравствуйте, Kh_Oleg, Вы писали:

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


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


K_O>>>Мне кажется, что преобразование происходит не на этапе компиляции.


I>>Да? А в исполняемом файле его L"привет" как хранится? Прямо так как написано, безо всякого преобразования в коды?

K_O>Как оказалось, в исполняемом файле хранится правильная Unicode строка. Очевидно, компилятор использует текущий locale, используемый в OC.

Действительно, в экзешнике лежит честная Юникодная строка. Тогда зачем им локаль? Ведь код 0x40xx явно указывает на кириллицу. Вобщем стало еще мутнее.

K_O>А вот почему stream не может отображать такие строки без явного задания locale — это уже отдельный вопрос, какие-то их внутренние заморочки.


— Каа, и ты принимаешь бой...
— Пляяяяяя.......

K_O>Кстати, а какой locale установлен в ОС топикстартера? Если английский/американский — тогда можно объяснить такое поведение, если русский — тогда не знаю.


Вроде бы по старту экзешника ставится американская локаль всегда. Во всяком случае она возвращается по запросу локали.
Re: тысяча второй раз про Юникод
От: Vain Россия google.ru
Дата: 13.10.09 18:02
Оценка:
Здравствуйте, pepsicoca, Вы писали:

P>Есть MSVC2003 и есть код.

может ещё stlport проверить для сравнения?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re: тысяча второй раз про Юникод
От: _DAle_ Беларусь  
Дата: 13.10.09 18:24
Оценка:
Здравствуйте, pepsicoca, Вы писали:

P>Добрый день.


...

Почитай тут: http://rsdn.ru/forum/cpp/550632.all.aspx
Автор: Зверёк Харьковский
Дата: 25.02.04
Re[4]: тысяча второй раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 08:44
Оценка:
Здравствуйте, pepsicoca, Вы писали:


P>1. Умеет ли редактор и транслятор MSVC работать в Юникодными исходниками? Если да, то где этот режим включается?


Да, умеет.
Компилятор смотрит на BOM-префикс текста и распознаёт UTF-8, UTF-16, UTF-16BE. Про UTF-32 не знаю, думаю, что не поймёт.
Редактор тоже смотрит на BOM. Смотри в диалоге Save As у кнопки Save[V] расширение, Save with encoding.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[2]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 09:14
Оценка:
Здравствуйте, pepsicoca, Вы писали:

P>1. Для китайского языка смещение гораздо больше, чем 128 символов из второй половины ASCII-таблицы. Как же в ASCIIшном исходнике задать китайскую строку, хотя бы и с помощью китайской локали?

Для китайского и им подобных языков, которым 128 символов мало, используются DBCS кодировки http://www.microsoft.com/typography/unicode/cs.htm
Re: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 09:31
Оценка:
Здравствуйте, pepsicoca, Вы писали:

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

Это от того, что все wZZZ функции из стандартных C/C++ библиотек это, грубо говоря, просто обертки над соответствующими функциями без префикса 'w', соответсвенно зависят от локали.

Отказаться от локали невозможно, т.к., например вывод
printf('%f\n', 3.14);

будет зависеть от локали (разделитель — точка или запятая).
Зачем указывать локаль при выводе на консоль? — чтобы дать хинт системе какие шрифты использовать для отображения символов. Ведь обычно шрифты делаются для определенного подмножества Unicode code point-ов.

Для полноценной работы с Unicode текстом средств стандартных C/C++ библиотек недостаточно, нужно использовать спец. библиотеки, ICU, например. Например tolower/toupper — locale specific, так что если вы получили произвольную unicode строку, tolower/toupper в общем случае к ней применять нельзя. А в ICU есть соответ. функции, которые от локали не зависят.
Re[7]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 09:49
Оценка:
Здравствуйте, 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
Re[9]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 09:53
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Кардинальное лечение, кстати — это ::setlocale(LC_CTYPE, "") — т.е. установить юзерскую кодировку. Можно и явно указать "rus_rus.1251", и "rus_rus.866".

К>Это повлияет не только на wcout, но и на wprintf.
Еще и на TranslateMessage, если цикл обработки сообщений писать руками.
Re[2]: тысяча второй раз про Юникод
От: pepsicoca  
Дата: 14.10.09 09:59
Оценка:
Здравствуйте, 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 есть соответ. функции, которые от локали не зависят.
Re[9]: тысяча второй раз про Юникод
От: pepsicoca  
Дата: 14.10.09 10:01
Оценка:
Здравствуйте, Кодт, Вы писали:

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


K_O>>А вот почему stream не может отображать такие строки без явного задания locale — это уже отдельный вопрос, какие-то их внутренние заморочки.


К>Всё очень просто, на самом деле. Ну, почти просто.


К>1. Консольный вывод — (мульти)байтовый, а не вайдовый. Поэтому wcout должен выполнять преобразование wctomb.


Чтобы выполнить преобразование wctomb не надо знать локаль. Вернее, не надо явно указывать локаль. То, что в данный момент пойдет на вывод кириллица можно понять из кода Юникода.
Re[3]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 11:46
Оценка:
Здравствуйте, 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.
Re[2]: тысяча второй раз про Юникод
От: Sergey Россия  
Дата: 14.10.09 11:55
Оценка:
Здравствуйте, alsemm, Вы писали:

A>Для полноценной работы с Unicode текстом средств стандартных C/C++ библиотек недостаточно, нужно использовать спец. библиотеки, ICU, например. Например tolower/toupper — locale specific, так что если вы получили произвольную unicode строку, tolower/toupper в общем случае к ней применять нельзя. А в ICU есть соответ. функции, которые от локали не зависят.


Эээ, а как эти функции с турецкой i поступают? Откуда догадываются что она турецкая?
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[3]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 12:08
Оценка:
Здравствуйте, 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
Re[10]: тысяча второй раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 12:09
Оценка:
Здравствуйте, pepsicoca, Вы писали:

К>>1. Консольный вывод — (мульти)байтовый, а не вайдовый. Поэтому wcout должен выполнять преобразование wctomb.

P>Чтобы выполнить преобразование wctomb не надо знать локаль. Вернее, не надо явно указывать локаль. То, что в данный момент пойдет на вывод кириллица можно понять из кода Юникода.

Нет. Нужно знать локаль выходного файлового потока. Он-то байтовый.
Потому что (w)printf и (w)cout пишут не прямо на экран!!!
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[4]: тысяча второй раз про Юникод
От: Sergey Россия  
Дата: 14.10.09 12:18
Оценка:
Здравствуйте, 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 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[4]: тысяча второй раз про Юникод
От: pepsicoca  
Дата: 14.10.09 12:21
Оценка:
Здравствуйте, 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.

???

Для того и Юникод ввели, чтобы о локали забыть. Главное, что буква "ю" в Юникоде однозначно представляется. Получив Юникодный символ "ю" система может (и должна) сама понять, что это кириллица, слазить за начертанием буквы "ю" в таблицу кириллических шрифтов и напечатать букву "ю".
Re[5]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 12:58
Оценка:
Здравствуйте, 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$ его у тебя купит, если хорошо получится.
Re[11]: тысяча второй раз про Юникод
От: pepsicoca  
Дата: 14.10.09 12:58
Оценка:
Здравствуйте, Кодт, Вы писали:

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


К>>>1. Консольный вывод — (мульти)байтовый, а не вайдовый. Поэтому wcout должен выполнять преобразование wctomb.

P>>Чтобы выполнить преобразование wctomb не надо знать локаль. Вернее, не надо явно указывать локаль. То, что в данный момент пойдет на вывод кириллица можно понять из кода Юникода.

К>Нет. Нужно знать локаль выходного файлового потока. Он-то байтовый.

К>Потому что (w)printf и (w)cout пишут не прямо на экран!!!

Нет. Не нужно знать локаль выходного файлового потока. Его локаль нужно переключить в соответствии с той локалью, которая указана в коде Юникода. То есть по коду Юникода система сама может (и должна) делать imbue соответствующей локали. Тогда из байтового выходного потока мы получим юникодный выходной поток. Каким, собственно, и должен быть поток с именем wcout. А байтовым должен быть (и есть) поток cout. Вот в потоке cout переключение локалей более чем оправдано. А в потоке wcout переключать локали это все равно, что рыбе зонтик.
Re[5]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 13:13
Оценка:
Здравствуйте, 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.
Re[12]: тысяча второй раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 13:23
Оценка:
Здравствуйте, 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).
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[6]: тысяча второй раз про Юникод
От: Sergey Россия  
Дата: 14.10.09 13:35
Оценка:
Здравствуйте, 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 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[6]: тысяча второй раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 13:39
Оценка:
Здравствуйте, alsemm, Вы писали:

A>В ICU есть два комплекта функций tolower/toupper:


Но с немецким эсцетом ни одна из них не справится (наверно?)
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[13]: тысяча второй раз про Юникод
От: pepsicoca  
Дата: 14.10.09 13:43
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, 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).
Re[7]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 18:38
Оценка:
Здравствуйте, Кодт, Вы писали:

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


A>>В ICU есть два комплекта функций tolower/toupper:


К>Но с немецким эсцетом ни одна из них не справится (наверно?)

Это когда, например, буква 'A' с кружком наверху представляется двумя символами? Думаю ICU-ые фнкции, которые конвертируют строки целиком, а не отдельные символы справятся.
Re[7]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 18:39
Оценка:
Здравствуйте, 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(), если не УГ после этого?
Re[8]: тысяча второй раз про Юникод
От: Sergey Россия  
Дата: 14.10.09 19:06
Оценка:
Здравствуйте, alsemm, Вы писали:

A>>>В ICU есть два комплекта функций tolower/toupper:


К>>Но с немецким эсцетом ни одна из них не справится (наверно?)

A>Это когда, например, буква 'A' с кружком наверху представляется двумя символами? Думаю ICU-ые фнкции, которые конвертируют строки целиком, а не отдельные символы справятся.

Не, это такая хрень которая маленькая выглядит как греческая бета, а большая — как SS. хз как ее ловеркейзить, насколько я понимаю, не любая SS является эсцетом.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[9]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 19:19
Оценка:
Здравствуйте, Sergey, Вы писали:

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


A>>>>В ICU есть два комплекта функций tolower/toupper:


К>>>Но с немецким эсцетом ни одна из них не справится (наверно?)

A>>Это когда, например, буква 'A' с кружком наверху представляется двумя символами? Думаю ICU-ые фнкции, которые конвертируют строки целиком, а не отдельные символы справятся.

S>Не, это такая хрень которая маленькая выглядит как греческая бета, а большая — как SS. хз как ее ловеркейзить, насколько я понимаю, не любая SS является эсцетом.

http://unicode.org/reports/tr21/tr21-5.html — спецификация unicode case mapping. http://unicode.org/reports/tr21/tr21-5.html#Introduction — в качестве вступления описаны эти самые SS и турецкая i, чтобы читатель оценил масштаб бедствия
Думаю ICU все это умеет, ибо http://www.unicodeconference.com/bios.htm:

Mark Davis
Sr. Internationalization Architect, Google Inc.

Dr. Mark Davis co-founded the Unicode project and has been the president of the Unicode Consortium since its incorporation in 1991. He is one of the key technical contributors to the Unicode specifications.

Mark founded and was responsible for the overall architecture of ICU (the premier Unicode software internationalization library), and architected the core of the Java internationalization classes. He also founded and is the chair of the Unicode CLDR project, and is a co-author of BCP 47 "Tags for Identifying Languages" (RFC 4646 and RFC 4646), used for identifying languages in all XML and HTML documents.

Since the start of 2006, Mark has been working on software internationalization at Google, focusing on effective and secure use of Unicode (especially in the index and search pipeline), the software internationalization libraries (including ICU), and stable international identifiers.

Re[8]: тысяча второй раз про Юникод
От: Sergey Россия  
Дата: 14.10.09 19:27
Оценка:
Здравствуйте, alsemm, Вы писали:

S>>...один комплект простой и работает неправильно, а второй — как в CRT

A>CRT-ая tolower конвертирует символ, а не строку. Так что всякие извращенные случаи, когда один заглавный символ превращается в несколько/0 прописных она обработать корректно не может.

С турецким проблема другая — без локали фиг догадаешься, что I должно конвертироваться в ı а не в i.

A>Аргумент CRT-ой tolower — символ юникода, но он обязательно должен быть из текущей локали http://opengroup.org/onlinepubs/007908799/xsh/towlower.html:

A>

A>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


A>Из этого следует, что если нужно конвертировать произвольную unicode строку, то перед вызовом towlower() для каждого символа строки надо определить какой он принадлежит локали (CRT для этого средств не предоставляет) и переключиться, если нужно. Однако, если даже правильно переключать локали результат будет не всегда корректным, т.к. towlower() не учитвает контекст символа.


A>Да, чуть не забыл, в случае, если sizeof(wchar_t) = 2 и кодировка не UCS2, а UTF16, т.е. надо иметь дело с surrogate pairs — towlower() вообще бесполезен.


A>И что такое CRT-ая towlower(), если не УГ после этого?


Да что вы все о towlower да о towlower, в CRT есть же в конце концов и _wcslwr. Которой для полного счастья только длины буфера не хватает.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[9]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 20:17
Оценка:
Здравствуйте, Sergey, Вы писали:

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


S>Да что вы все о towlower да о towlower, в CRT есть же в конце концов и _wcslwr. Которой для полного счастья только длины буфера не хватает.

_wcslwr может быть по разному реализована: может так — http://danielcastelao.org/apuntes/software/programacion/VisualC/VC98/CRT/SRC/WCSLWR.C (повезло), а может так — http://doxygen.reactos.org/d2/d20/wcslwr_8c_source.html, http://195.19.138.139:3000/p/SOFTWARE/temp/CBuilder5/Source/RTL/source/locale/strlwr.c. А ICU она и в африке ICU.
Re[8]: тысяча второй раз про Юникод
От: Кодт Россия  
Дата: 14.10.09 20:21
Оценка:
Здравствуйте, alsemm, Вы писали:

К>>Но с немецким эсцетом ни одна из них не справится (наверно?)

A>Это когда, например, буква 'A' с кружком наверху представляется двумя символами? Думаю ICU-ые фнкции, которые конвертируют строки целиком, а не отдельные символы справятся.

Эсцет — это буква, похожая на бету — на самом деле, лигатура готических строчных sz / ss. В заглавном виде не существовала (сейчас, вроде бы, есть подвижка сделать её и заглавной тоже). Соответственно, честный toupper — это не одиночный символ, а двойной: SS (или SZ в зависимости от контекста?)
Перекуём баги на фичи!
Re[9]: тысяча второй раз про Юникод
От: alsemm Россия  
Дата: 14.10.09 21:07
Оценка:
Здравствуйте, Кодт, Вы писали:

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


К>>>Но с немецким эсцетом ни одна из них не справится (наверно?)

A>>Это когда, например, буква 'A' с кружком наверху представляется двумя символами? Думаю ICU-ые фнкции, которые конвертируют строки целиком, а не отдельные символы справятся.

К>Эсцет — это буква, похожая на бету — на самом деле, лигатура готических строчных sz / ss. В заглавном виде не существовала (сейчас, вроде бы, есть подвижка сделать её и заглавной тоже). Соответственно, честный toupper — это не одиночный символ, а двойной: SS (или SZ в зависимости от контекста?)

Та которая строки, а не отдельные символы конвертирует должна справиться
Автор: alsemm
Дата: 14.10.09
Re: тысяча второй раз про Юникод
От: byleas  
Дата: 27.10.09 15:02
Оценка:
Здравствуйте, pepsicoca, Вы писали:

P> Зачем еще указывать локаль?

Потому что файловые потоки (точнее, их буфера) в С++ принудительно конвертируют строки в ANSI по текущей кодовой страницей локали, а вывод в консоль в VC сделан именно через них. А из-за разницы между текущей кодовой страницей потока (к примеру, 1251) и кодовой страницей консоли (866) получаем означенную проблему.
Re[11]: тысяча второй раз про Юникод
От: byleas  
Дата: 27.10.09 15:17
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Нужно знать локаль выходного файлового потока. Он-то байтовый.

Кстати, а почему так сделано. Вопрос не про fstream, а про wfstream.

Для портируемости? Сомневаюсь, что её можно достигнуть, оперируя у себя на машине юникодом и сохраняя его в ANSI кодировке на основании текущей локали. Ведь информация о последней не содержится в файле. Почему бы не сделать сохранение wfstream'a в файл в юникоде? Или ноги растут от того, что wchar_t в С++ — это не юникод, а просто wide character (и изначально в старых компиляторах он был простым typedef'ом от unsigned short)?

В новый стандарт добавили "истинно юникодовые" символы — char16_t & char32_t (UTF16/32), вот только ситуация с потоками осталась прежней.

В VC8 добавили, кстати, возможность сохранения данных в файл в юникоде — через суффикс имени файла "cch=encoding". Костыль, конечно, но хоть как-то теперь работает.
iostream unicode
Re[12]: тысяча второй раз про Юникод
От: Sergey Россия  
Дата: 27.10.09 16:02
Оценка:
Здравствуйте, byleas, Вы писали:

К>>Нужно знать локаль выходного файлового потока. Он-то байтовый.

B>Кстати, а почему так сделано. Вопрос не про fstream, а про wfstream.

B>Для портируемости?


Именно.

B>Сомневаюсь, что её можно достигнуть, оперируя у себя на машине юникодом и сохраняя его в ANSI кодировке на основании текущей локали. Ведь информация о последней не содержится в файле.


А это уже не из стандарта, а (странная) особенность реализации.

B>Почему бы не сделать сохранение wfstream'a в файл в юникоде?


В какой формат будем сохранять — UTF-16 BE или UTF-16 LE? А если мне в другой надо? А с текущим положением дел, я могу написать свой codecvt, который складывает байты в том порядке, в котором мне надо. Так что не надо нам таких усовершенствований, у меня из-за них программа перестанет работать.

B> Или ноги растут от того, что wchar_t в С++ — это не юникод, а просто wide character (и изначально в старых компиляторах он был простым typedef'ом от unsigned short)?


B>В новый стандарт добавили "истинно юникодовые" символы — char16_t & char32_t (UTF16/32), вот только ситуация с потоками осталась прежней.


B>В VC8 добавили, кстати, возможность сохранения данных в файл в юникоде — через суффикс имени файла "cch=encoding". Костыль, конечно, но хоть как-то теперь работает.


Копипастишь к себе codecvt_null из boost/archive — и работает везде. При необходимости фиксишь порядок байт как требуется.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.