Rating@Mail.ru

Форум сайта "Виртуальная энциклопедия "Linux по-русски"


Текущее время: 24 май 2017, 13:05

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 33 ]  На страницу Пред.  1, 2, 3, 4  След.
Автор Сообщение
 Заголовок сообщения: Re: локализация строк в C-коде
Непрочитанное сообщениеДобавлено: 28 авг 2013, 23:36 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9440
Откуда: Харьков
Виктория писал(а):
В качестве примеров я брала файлы с расширением py :-)

Это, наверное, имеется в виду: viewtopic.php?f=31&t=3029&start=10#p8988 ?

Но чтобы не создавать путаницу (ведь здесь тема называется "локализация строк в C-коде" ;-) ) давайте я создам отдельную коротенькую ему по локализации в Python, и там попробуем разобраться.
Чтобы снять всякие сомнения ... в возможности лёгкого переноса проектов между Linux & Windows ... и какие там неожиданности могут подстерегать.

Вот такая тема: локализация в Python


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: локализация строк в C-коде
Непрочитанное сообщениеДобавлено: 09 ноя 2013, 18:46 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9440
Откуда: Харьков
Olej писал(а):
1. "широкие" символы wchar_t, которые являются (в POSIX) прямым изображением UNICODE кодировки UTF-32, и, естественно, каждый символ занимает 4 байта;

2. многобайтные представления, которые хоть и загружены в char[], но в кодировке UTF-8 (т.е. тоже UNICODE, но в другой кодировке); они непригодны для непосредственной обработки строковыми функциями + функции преобразований (mbtowc(), wctomb(), mblen(), mbrtowc(), wcrtomb(), mbrlen() и т.д.), для преобразования в wchat_t[] и обратно (См.: Многобайтовые символы, mbchar(3C))


Вот неплохое (простое) изложение соотношения мультибайтного представления (UTF-8) символов и широкого (wchar_t): 18. Расширение Символов (это из первоисточника описывающего C библиотеки GNU/GCC).
Вполне достаточно для того, чтобы делать для себя преобразования из одной формы в другую.


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: локализация строк в C-коде
Непрочитанное сообщениеДобавлено: 09 ноя 2013, 19:09 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9440
Откуда: Харьков
Olej писал(а):
Olej писал(а):
1. "широкие" символы wchar_t, которые являются (в POSIX) прямым изображением UNICODE кодировки UTF-32, и, естественно, каждый символ занимает 4 байта;

2. многобайтные представления, которые хоть и загружены в char[], но в кодировке UTF-8 (т.е. тоже UNICODE, но в другой кодировке); они непригодны для непосредственной обработки строковыми функциями + функции преобразований (mbtowc(), wctomb(), mblen(), mbrtowc(), wcrtomb(), mbrlen() и т.д.), для преобразования в wchat_t[] и обратно (См.: Многобайтовые символы, mbchar(3C))


Вот неплохое (простое) изложение соотношения мультибайтного представления (UTF-8) символов и широкого (wchar_t): 18. Расширение Символов.
Вполне достаточно для того, чтобы делать для себя преобразования из одной формы в другую.


В связи с этим любопытный пример:
Код:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>

const char buf[] = "русскоязычная строка";

int main( int argc, char **argv ) {
   wchar_t wbuf[ 40 ];
   printf( "значение MB_CUR_MAX до вызова setlocale(): %d [ locale = %s ]\n",
           MB_CUR_MAX, setlocale( LC_ALL, NULL ) );
   setlocale( LC_ALL, "" );   // только после этого работают преобразования!
   printf( "значение MB_CUR_MAX после вызова setlocale(): %d [ locale = %s ]\n",
           MB_CUR_MAX, setlocale( LC_ALL, NULL ) );
   printf( "исходная UTF-8 строка: '%s', длина в байтах = %d\n", buf, strlen( buf ) );
   int n = -1, i;
   char *p;
   for( i = 0, p = (char*)buf; n != 0; i++ )
      p += ( n = mbtowc( wbuf + i, p, MB_CUR_MAX ) );
   printf( "преобразованная строка: '%ls'\n"
           "длина преобразованной wchar_t строки = %d символов\n",
           wbuf, wcslen( wbuf ) );
   return 0;
}


Любопытного здесь то, что до вызова setlocale( LC_ALL, "" ) в программе установлена локализация C, и никакое преобразование русскоязычного текста (UTF-8) ... да и вообще любая работа с многобайтным представлением русского языка невозможны!
И любой вызов функций mb*() будет возвращать только ошибку.

Код:
olej@notebook:~/2013_WORK/examples.tools.DRAFT/locale_c$ ./loctest
значение MB_CUR_MAX до вызова setlocale(): 1 [ locale = C ]
значение MB_CUR_MAX после вызова setlocale(): 6 [ locale = ru_UA.UTF-8 ]
исходная UTF-8 строка: 'русскоязычная строка', длина в байтах = 39
преобразованная строка: 'русскоязычная строка'
длина преобразованной wchar_t строки = 20 символов


Вложения:
loctest.c [1.07 КБ]
Скачиваний: 336
Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: локализация строк в C-коде
Непрочитанное сообщениеДобавлено: 07 янв 2015, 22:56 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9440
Откуда: Харьков
Интересные эффекты с локализацией наблюдаются в Java ... описаны вот здесь: java.выбор_коллекции.
Такие вещи, в общем, не зависимы от языка программирования ... и наводят на вопросы к размышлениям.


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: локализация строк в C-коде
Непрочитанное сообщениеДобавлено: 04 фев 2016, 18:16 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9440
Откуда: Харьков
Ещё раз возвращаясь к локализации.
Причем не только в C, но и C++ ... поскольку там эти вещи обстоят аналогично.

P.S. Напомню, что C++ программы используют (кроме своей собственной libstdc++.so) стандартную библиотеку C/POSIX libc.so - без библиотеки C код C++ недееспособный, он не удет выполняться. В этом легко удостовериться лишний раз, посмотрев на маленькие программки (out1.cc & out5.c), которые ниже рассмотрим:
Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ ldd out1
   linux-gate.so.1 =>  (0xb77cf000)
   libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xb76c4000)
   libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb76a7000)
   libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb74f8000)
   libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb74b2000)
   /lib/ld-linux.so.2 (0xb77d0000)
olej@nvidia ~/2016_WORK/in.WORK/out $ ldd out5
   linux-gate.so.1 =>  (0xb7716000)
   libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7545000)
   /lib/ld-linux.so.2 (0xb7717000)


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: локализация строк в C-коде
Непрочитанное сообщениеДобавлено: 04 фев 2016, 18:25 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9440
Откуда: Харьков
Olej писал(а):
Ещё раз возвращаясь к локализации.


Итак:
Код:
int main() {
   locale::global( locale( "" ) );
   wcout << L"строка" << endl;
   return 0;
}

Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ ./out1
строка

Всё замечательно: выводится русский текст, заданный символьной константой в широких символах (UTF-32), отлично выводится на терминал ... и на другие места будет так же ;-) .
Вот так и будем поступать.

Если убрать строку с locale::... - то получим явное не то:
Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ ./out1
??????

Этой строкой мы устанавливаем локаль программы в ту, которая установлена в системе по умолчанию:
Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ locale
LANG=ru_RU.utf8
LANGUAGE=
LC_CTYPE="ru_RU.utf8"
LC_NUMERIC="ru_RU.utf8"
LC_TIME="ru_RU.utf8"
LC_COLLATE="ru_RU.utf8"
LC_MONETARY="ru_RU.utf8"
LC_MESSAGES="ru_RU.utf8"
LC_PAPER="ru_RU.utf8"
LC_NAME="ru_RU.utf8"
LC_ADDRESS="ru_RU.utf8"
LC_TELEPHONE="ru_RU.utf8"
LC_MEASUREMENT="ru_RU.utf8"
LC_IDENTIFICATION="ru_RU.utf8"
LC_ALL=


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: локализация строк в C-коде
Непрочитанное сообщениеДобавлено: 04 фев 2016, 18:31 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9440
Откуда: Харьков
Olej писал(а):
Olej писал(а):
Ещё раз возвращаясь к локализации.

Этой строкой мы устанавливаем локаль программы в ту, которая установлена в системе по умолчанию:

Можно (только осторожно :lol: ) и явно заказать локаль для программы (хоть китайскую):
Код:
   locale loc;
   try {
      loc = std::locale ( "ru_RU.utf8" );
   }
   catch( std::runtime_error ) {
      loc = std::locale ( loc, "", std::locale::ctype );
   }
   locale::global( loc );

Но делаем это в блоке try, потому что если такая локаль не установлена в системе (не установлена, не обязательно является дефаултной), то мы поймаем исключение.


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: локализация строк в C-коде
Непрочитанное сообщениеДобавлено: 04 фев 2016, 18:44 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9440
Откуда: Харьков
Olej писал(а):
Вот так и будем поступать.


Но! :
Код:
int main() {
   locale::global( locale( "" ) );
   cout << "строка1" << endl;
   wcout << L"строка2" << endl;
   cout << "строка3" << endl;
   wcout << L"строка4" << endl;
   return 0;
}

Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ ./out2a
строка1
AB@>:02
строка3
AB@>:04


И:
Код:
int main() {
   locale::global( locale( "" ) );
   wcout << L"строка1" << endl;
   cout << "строка2" << endl;
   wcout << L"строка3" << endl;
   cout << "строка4" << endl;
   return 0;
}

Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ ./out2b
строка1
строка3


В (выходной) поток можно писать только строки одного рода: либо нативные char, либо широкие символы wchar_t. Поток настраивается под первый пришедший тип символов, и вывод другого типа символов идёт вразнос. Причём по-разному: вывод wcout после cout выводит кракозябры (локаль к этому не имеет отношения!), а вывод cout после wcout просто уходит в никуда (/dev/null).

Документация упоминает об этом:
Цитата:
A program should not mix output operations on wcout with output operations on cout (or with other narrow-oriented output operations on stdout): Once an output operation has been performed on either, the standard output stream acquires an orientation (either narrow or wide) that can only be safely changed by calling freopen on stdout.


Исходя из этой фразы мы можем решить проблему:
Код:
int main() {
   locale::global( locale( "" ) );
   cout << "строка1" << endl;
   stdout = freopen( "/dev/stdout", "w", stdout );
   wcout << L"строка2" << endl;
   stdout = freopen( "/dev/stdout", "w", stdout );
   cout << "строка3" << endl;
   stdout = freopen( "/dev/stdout", "w", stdout );
   wcout << L"строка4" << endl;
   return 0;
}

Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ ./out3
строка1
строка2
строка3
строка4


P.S. Сразу возьмём на заметку: freopen() - API POSIX, C ... т.е. проблема потоков не в C++, а в C библиотеке.


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: локализация строк в C-коде
Непрочитанное сообщениеДобавлено: 04 фев 2016, 19:01 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9440
Откуда: Харьков
Olej писал(а):
Исходя из этой фразы мы можем решить проблему:

Но это решение - архитектурно-зависимое (/dev/sysout).
А как быть тем C++ писателям, которые любят этим заниматься в C++ на Windows :oops: ... или любой другой C++ системе?
В документации тоже ест подсказка:
Цитата:
If filename is a null pointer, the function attempts to change the mode of the stream. Although a particular library implementation is allowed to restrict the changes permitted, and under which circumstances.


Код:
int main() {
   locale::global( locale( "" ) );
   cout << "строка1" << endl;
   stdout = freopen( NULL, "w", stdout );
   wcout << L"строка2" << endl;
   stdout = freopen( NULL, "w", stdout );
   cout << "строка3" << endl;
   stdout = freopen( NULL, "w", stdout );
   wcout << L"строка4" << endl;
   return 0;
}

Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ ./out4
строка1
строка2
строка3
строка4


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: локализация строк в C-коде
Непрочитанное сообщениеДобавлено: 04 фев 2016, 19:07 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 9440
Откуда: Харьков
Olej писал(а):
P.S. Сразу возьмём на заметку: freopen() - API POSIX, C ... т.е. проблема потоков не в C++, а в C библиотеке.

Разобравшись с C++ (мне кажется что в исчерпывающей мере), самое время вернуться в C:
Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ make
cc     out5a.c   -o out5a
cc     out5b.c   -o out5b


Код:
int main() {
   setlocale( LC_ALL, "" );
   char cs[] = "строка";
   wchar_t ws[] = L"строка";
   printf( "%s\n", cs );
   printf( "%ls\n", ws );
   printf( "%s\n", cs );
   printf( "%ls\n", ws );
   return 0;
}

Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ ./out5a
строка
строка
строка
строка


Код:
int main() {
   setlocale( LC_ALL, "" );
   char cs[] = "строка";
   wchar_t ws[] = L"строка";
   printf( "%ls\n", ws );
   printf( "%s\n", cs );
   printf( "%ls\n", ws );
   printf( "%s\n", cs );
   return 0;
}

Код:
olej@nvidia ~/2016_WORK/in.WORK/out $ ./out5b
строка
строка
строка
строка


1. setlocale( LC_ALL, "" ); - выполняет здесь те же функции, что и locale::global( locale( "" ) ); в C++ коде.
2. без него работа с широкими символами будет невозможна, и что самое противное - преобразования из UTF-8 в wchar_t функциями группы mb*() - работать не будут.
3. но самый важный результат: printf() будет работать и с типовыми и с широкими символами вперемешку любым образом.


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 33 ]  На страницу Пред.  1, 2, 3, 4  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2


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

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB
[ Time : 0.038s | 20 Queries | GZIP : On ]