Кодирование-декодирование в UTF-8

 
+
-
edit
 

HolyBoy

аксакал

Здравствуйте.

Столкнулся с не совсем понятным для меня пока что явлением: используя перловые функции для кодирования в юникод, получаю кракозябры при кодировании русскоязычного текста, полученного с юникодной консоли.

Покурив ссылки, в частности вот эту utf8 - perldoc.perl.org, пробую:

code perl
  1. #!/usr/bin/perl -w
  2.  
  3. use utf8;
  4.  
  5. print ("Как Вас зовут? ");
  6. $name= <STDIN>;
  7.  
  8. chomp ($name);
  9.  
  10. utf8::encode($name);
  11.  
  12. print "$name\n";


code text
  1. $ ./test.pl
  2. Wide character in print at ./test.pl line 5.
  3. Как Вас зовут? 123
  4. 123
  5. ~/programming/perl $ ./test.pl
  6. Wide character in print at ./test.pl line 5.
  7. Как Вас зовут? wer
  8. wer
  9. ~/programming/perl $ ./test.pl
  10. Wide character in print at ./test.pl line 5.
  11. Как Вас зовут? 12er
  12. 12er
  13. ~/programming/perl $ ./test.pl
  14. Wide character in print at ./test.pl line 5.
  15. Как Вас зовут? er12
  16. er12
  17. ~/programming/perl $ ./test.pl
  18. Wide character in print at ./test.pl line 5.
  19. Как Вас зовут? цув
  20. ÑÑв
  21. ~/programming/perl $ ./test.pl
  22. Wide character in print at ./test.pl line 5.
  23. Как Вас зовут? 12цув
  24. 12ÑÑв
  25. ~/programming/perl $ ./test.pl
  26. Wide character in print at ./test.pl line 5.
  27. Как Вас зовут? цув12
  28. ÑÑв12


При этом локаль у меня юникодная:
code text
  1. $ locale
  2. LANG=ru_RU.UTF-8
  3. LC_CTYPE="ru_RU.UTF-8"
  4. LC_NUMERIC="ru_RU.UTF-8"
  5. LC_TIME="ru_RU.UTF-8"
  6. LC_COLLATE="ru_RU.UTF-8"
  7. LC_MONETARY="ru_RU.UTF-8"
  8. LC_MESSAGES="ru_RU.UTF-8"
  9. LC_PAPER="ru_RU.UTF-8"
  10. LC_NAME="ru_RU.UTF-8"
  11. LC_ADDRESS="ru_RU.UTF-8"
  12. LC_TELEPHONE="ru_RU.UTF-8"
  13. LC_MEASUREMENT="ru_RU.UTF-8"
  14. LC_IDENTIFICATION="ru_RU.UTF-8"
  15. LC_ALL=ru_RU.UTF-8


Кое-какие дополнительные тесты показали, что данная функция каждый байт из $name считает нужным перевести в UTF-8. Почему так? Потому что правой пятке программистов захотелось такое или какие-то соображения таки были?
 
+
-
edit
 

Balancer

администратор
★★★★★
Последний раз на Перле с UTF-8 работал лет пять назад. Тогда проблем не было. Локаль в UTF-8 была, работал как с родной локалью, так и с чтением/записью в CP1251/KOI8-R.
 
+
-
edit
 

HolyBoy

аксакал

Balancer> Последний раз на Перле с UTF-8 работал лет пять назад. Тогда проблем не было. Локаль в UTF-8 была, работал как с родной локалью, так и с чтением/записью в CP1251/KOI8-R.

Это я решил разобраться с одной системной утилитой. У неё как раз запись некоторых значений в базу идёт после преобразований исходных с помощью utf8Encode. Но когда оное выполняется для юникодного текста, то получается такая вот бяка:

code text
  1. исходное
  2. привет
  3.  
  4. результат
  5. пÑивеÑ


Само собой, проблема решается с помощью убирания этой вот функции utf8Encode, но хотелось бы разобраться, почему она вообще появляется и поправить, если возможно, этот скрипт без столь радикальных действий, как выключение функции из работы.
 
+
-
edit
 

Mishka

модератор
★★★
Ты запиши в файлик и прочитай программкой, которая UTF-8 понимает. У меня было такое в С++, когда всякие принты использовались. Или брось сюда двоичное значение побайтово.
 6.06.0
+
-
edit
 

HolyBoy

аксакал

Всё, я похоже решил проблему частично.
Оказывается, автор утилиты скинул в отдельный файл определение функции utf8Encode вот в таком виде:

code perl
  1. sub utf8Encode {
  2.     my $arg = shift;
  3.  
  4.     return to_utf8(
  5.         -string  => $arg,
  6.         -charset => 'ISO-8859-1',
  7.     );
  8. }
  9.  
  10. sub utf8Decode {
  11.     my $arg = shift;
  12.  
  13.     return from_utf8(
  14.         -string  => $arg,
  15.         -charset => 'ISO-8859-1',
  16.     );
  17. }


Соответственно, я нашёл Unicode::MapUTF8 - A generic encoding to/from UTF8 convertor , потестировал
code perl
  1. #!/usr/bin/perl -w
  2.  
  3. #use utf8;
  4. use Unicode::MapUTF8 qw(to_utf8 from_utf8);
  5.  
  6. print ("Как Вас зовут? ");
  7. $name= <STDIN>;
  8.  
  9. chomp ($name);
  10.  
  11. #utf8::encode($name);
  12. my $output = to_utf8({ -string => $name, -charset => 'utf8' });
  13.  
  14. print "$output\n";


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

Но… как-то оно не изЯЧно. Во-первых, Changes из ссылки рассказывает, что последний раз эти функции менялись в 2001, а ссылка из самого первого сообщения вроде намекает на то, что сейчас более свежие и актуальные средства появились. Во-вторых, если кто-то вдруг вздумает засунуть в качестве аргумента не UTF-8, то может получиться нехорошо. Если я уверен в том, что локально на машине эта программа получит UTF-8 стопроцентно, то в данных с других машин, в частности, виндовых, я не уверен. Если нет способа надёжно распознать кодировку, то придётся, наверное, потестировать и смириться с тем, что есть.
 
+
-
edit
 

Harsky

опытный

а зачем ты вообще пытаешься куда-то конвертировать ввод?

code perl
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use utf8;
  4.  
  5. print ("Как Вас зовут? ");
  6. my $name= <STDIN>;
  7.  
  8. print $name



harsky-mac:bin harsky$ locale
LANG="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
LC_CTYPE="ru_RU.UTF-8"
LC_MESSAGES="ru_RU.UTF-8"
LC_MONETARY="ru_RU.UTF-8"
LC_NUMERIC="ru_RU.UTF-8"
LC_TIME="ru_RU.UTF-8"
LC_ALL="ru_RU.UTF-8"

harsky-mac:bin harsky$ ./test.pl
Wide character in print at ./test.pl line 5.
Как Вас зовут? вася
вася
 3.0.63.0.6
+
-
edit
 

Balancer

администратор
★★★★★
Harsky> Wide character in print at ./test.pl line 5.

Ну ленивый народ пошёл :) Пришлось пойти погуглить.



code perl
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use utf8;
  4. use open qw(:std :utf8);
  5.  
  6. print ("Как Вас зовут? ");
  7. my $name= <STDIN>;
  8.  
  9. print $name


$ perl test.pl
Как Вас зовут? Рома
Рома
 
+
-
edit
 

HolyBoy

аксакал

Harsky> а зачем ты вообще пытаешься куда-то конвертировать ввод?

Смотри, это не я пытаюсь, это автор пытается что-то куда-то конвертировать. А я вижу неверную работу утилиты и разбираю, почему ж она не работает как надо.
 
+
-
edit
 

Harsky

опытный

Harsky>> Wide character in print at ./test.pl line 5.
Balancer> Ну ленивый народ пошёл :) Пришлось пойти погуглить.
да ладно, у меня целых 2 отмазки есть ;)

может лучше так (конкретно для этого примера)?
code perl
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use utf8;
  4.  
  5. binmode(STDOUT,':utf8');
  6. binmode(STDIN,':utf8');
  7. print ("Как Вас зовут? ");
  8. my $name= <STDIN>;
  9.  
  10. print $name
 3.0.63.0.6
+
-
edit
 

Harsky

опытный

HolyBoy> Если нет способа надёжно распознать кодировку, то придётся, наверное, потестировать и смириться с тем, что есть.

а прога консольная? или это у тебя для отладки кусочек работает с консолью?
 3.0.63.0.6
+
-
edit
 

HolyBoy

аксакал

Harsky> а прога консольная? или это у тебя для отладки кусочек работает с консолью?

Консольная. Да, для отладки. Чтобы разобраться.
 
+
-
edit
 

Harsky

опытный

тогда при работе в unix можно в переменных окружения проверить локаль. а в винде... проверить не на чем, но кажется там есть консольная команда chcp, которая тебе скажет/поменяет по крайней мере кодовую страницу ввода/вывода



Портал информации для веб-разработчиков


Портал информации для веб-разработчиков

// www.shkodenko.kiev.ua
 
 3.0.63.0.6
+
-
edit
 

HolyBoy

аксакал

Harsky> тогда при работе в unix можно в переменных окружения проверить локаль. а в винде... проверить не на чем, но кажется там есть консольная команда chcp, которая тебе скажет/поменяет по крайней мере кодовую страницу ввода/вывода


Дык, я ж писал, что в лине локаль юникодная. А точнее всё написано тут Кодирование-декодирование в UTF-8 [HolyBoy#23.02.09 20:53]
Моё беспокойство вызвано тем, что эта утиль может неправильно распознать поток символов от другой программы, которая получает данные от винды. Но это так, теоретизирование. Вдруг, если… и тд.

Реально же, сабжевая утилита будет запускаться только на линуховой машине, так что я спокойно пропатчил её.
 

в начало страницы | новое
 
Поиск
Настройки
Твиттер сайта
Статистика
Рейтинг@Mail.ru