Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > utf2win


Автор: rcdimon 4.2.2006, 14:29
Есть строка, в utf8 и мне нужно ее перекодировать в win-1251 для вывода на экран!

Для этого я неизвестно где взял вот такую процедуру

Код

sub utf2win
{
  my $in=shift;
  my @in=split(//,$in);
  my $len=@in;
  my @out;
  my $byte2=0;
  for ($c=0;$c<$len;$c++)
  {
    $i=ord($in[$c]);
    if ($i<=127)
    {
         push @out,$s[$c];
    }
    elsif ($byte2>0)
    {
        if (($i==129) && ($byte2==208)) {
            $newi=168; # ¨
        }
        elsif (($i==145) && ($byte2==209)) {
            $newi=184; # ¸
        }
        elsif (($i>=144) && ($i<=191)) {
            $newi=$i+48;
        }
        elsif (($i>=128) && ($i<=143)) {
            $newi=$i+112;
        }
        else {
            $newi=35;
        }
        push @out,chr($newi);
        $byte2=0;
    }
    elsif (($i==208) || ($i==209)) {
      $byte2=$i;}
  }
  return join('',@out);
}


Если в нее сунуть данные из переменной она ответит пустой строкой! Но если считать данные из файла тоже в кодировке utf8 То она переконвертирует.

Тогда я свою переменную сначала пихал в файл, потом читал его и вводил в процедуру- тогда все ОК.

Но прямо из переменной не хочет конвертировать и все!

Тогда я решил проверить чем же отличаются данные из файла и из переменной. Если просто вывести на экран- то ничем. Для детальной проверки сделал так

Код

@a = split(//,$a);

foreach (@a){
    print ord($_) . '<br>';
}


и у меня получились очень интерсеные результаты smile

Из файла вот:
Код

75<br>105<br>110<br>100<br>101<br>114<br>46<br>114<br>117<br>32<br>45<br>32<br>208<br>148<br>208<br>181<br>209<br>130<br>209<br>129<br>208<br>186<br>208<br>184<br>208<br>181<br>32<br>208<br>189<br>208<br>190<br>208<br>178<br>208<br>190<br>209<br>129<br>209<br>130<br>208<br>184<br>


а из переменной вот

Код

75<br>105<br>110<br>100<br>101<br>114<br>46<br>114<br>117<br>32<br>45<br>32<br>1044<br>1077<br>1090<br>1089<br>1082<br>1080<br>1077<br>32<br>1085<br>1086<br>1074<br>1086<br>1089<br>1090<br>1080<br>



Откуда код символа может быть 1082, 180 и т.д! Я просто в шоке..

Помогите пожалуйста с перекодировкой!

Автор: sharq 4.2.2006, 15:42
rcdimon
perldoc perlunicode
perldoc perluniintro

Код

use Encode 'from_to';

my $data = 'привет';
from_to($data, 'cp1251', 'utf8');
print 'Unicode: '.$data, "\n";
from_to($data, 'utf8', 'cp1251');
print 'Cyrillic:  '.$data, "\n";


smile

Автор: rcdimon 4.2.2006, 16:06
Software error:

Cannot decode string with wide characters at q:/usr/perl58/lib/Encode.pm line 186.

For help, please send mail to the webmaster (rcdimon), giving this error message and the time and date of the error.
Добавлено @ 16:08
Кстати если интересно откуда я беру данные для перекодировки- то я получаю их из модуля XML::RSS и пытаюсь их перекодировать в windows-1251 а XML::RSS в процессе своей работы входящие в него данные перекодирует в UTF-8

Автор: sharq 4.2.2006, 17:37
rcdimon ты мой пример запускал?

у меня вот что:
Код

>perl utf2win.pl
Unicode: РїСЂРёРІРµС‚
Cyrillic:  привет



Автор: rcdimon 4.2.2006, 20:29
ДА. Работает если давать ему нормальные данные... НО smile Мне надо перекодировать то, что выдает XML::RSS! А вот при перекодировки его ответа как раз и происходит ошибка

Software error:
Cannot decode string with wide characters at q:/usr/perl58/lib/Encode.pm line 186.
For help, please send mail to the webmaster (rcdimon), giving this error message and the time and date of the error.

Автор: rcdimon 4.2.2006, 22:15
Короче rod() от символов получается больше чем 255. Поэтому он и не хочет эти символы перекодировать! А почему такие символы берутся- непонятно smile

Автор: korob2001 5.2.2006, 03:27
Код

use Text::Iconv;
my $conv = Text::Iconv->new("UTF-8", "WINDOWS-1251");
my $string = "Строка из XML в кодировке utf-8";
print $conv->convert( $string );

Автор: rcdimon 5.2.2006, 08:52
А никак нельзя обойтись без подключения нестандартного модуля?

Автор: Sadok 6.2.2006, 11:13
rcdimon
Цитата
А никак нельзя обойтись без подключения нестандартного модуля?

Вот тебе хэш,по нему и заменяй
Код

%code2char = (

# CYRILLIC 1251

1025 => "Ё",
1040 => "А",
1041 => "Б",
1042 => "В",
1043 => "Г",
1044 => "Д",
1045 => "Е",
1046 => "Ж",
1047 => "З",
1048 => "И",
1049 => "Й",
1050 => "К",
1051 => "Л",
1052 => "М",
1053 => "Н",
1054 => "О",
1055 => "П",
1056 => "Р",
1057 => "С",
1058 => "Т",
1059 => "У",
1060 => "Ф",
1061 => "Х",
1062 => "Ц",
1063 => "Ч",
1064 => "Ш",
1065 => "Щ",
1066 => "Ъ",
1067 => "Ы",
1068 => "Ь",
1069 => "Э",
1070 => "Ю",
1071 => "Я",
1072 => "а",
1073 => "б",
1074 => "в",
1075 => "г",
1076 => "д",
1077 => "е",
1078 => "ж",
1079 => "з",
1080 => "и",
1081 => "й",
1082 => "к",
1083 => "л",
1084 => "м",
1085 => "н",
1086 => "о",
1087 => "п",
1088 => "р",
1089 => "с",
1090 => "т",
1091 => "у",
1092 => "ф",
1093 => "х",
1094 => "ц",
1095 => "ч",
1096 => "ш",
1097 => "щ",
1098 => "ъ",
1099 => "ы",
1100 => "ь",
1101 => "э",
1102 => "ю",
1103 => "я",
1105 => "ё",
);

Автор: rcdimon 6.2.2006, 13:24
Пасиба smile

Автор: nitr 14.2.2006, 01:40
Код


$content; 
utf2str(\$content);

sub utf2str {
  my $str = shift;
  die "$str is not a scalar reference" unless ref($str) eq 'SCALAR';
  $$str =~ s/\x{410}/А/g;
  $$str =~ s/\x{411}/Б/g;
  $$str =~ s/\x{412}/В/g;
  $$str =~ s/\x{413}/Г/g;
  $$str =~ s/\x{414}/Д/g;
  $$str =~ s/\x{415}/Е/g;
  $$str =~ s/\x{401}/Ё/g;
  $$str =~ s/\x{416}/Ж/g;
  $$str =~ s/\x{417}/З/g;
  $$str =~ s/\x{418}/И/g;
  $$str =~ s/\x{419}/Й/g;
  $$str =~ s/\x{41A}/К/g;
  $$str =~ s/\x{41B}/Л/g;
  $$str =~ s/\x{41C}/М/g;
  $$str =~ s/\x{41D}/Н/g;
  $$str =~ s/\x{41E}/О/g;
  $$str =~ s/\x{41F}/П/g;
  $$str =~ s/\x{420}/Р/g;
  $$str =~ s/\x{421}/С/g;
  $$str =~ s/\x{422}/Т/g;
  $$str =~ s/\x{423}/У/g;
  $$str =~ s/\x{424}/Ф/g;
  $$str =~ s/\x{425}/Х/g;
  $$str =~ s/\x{426}/Ц/g;
  $$str =~ s/\x{427}/Ч/g;
  $$str =~ s/\x{428}/Ш/g;
  $$str =~ s/\x{429}/Щ/g;
  $$str =~ s/\x{42A}/Ъ/g;
  $$str =~ s/\x{42B}/Ы/g;
  $$str =~ s/\x{42C}/Ь/g;
  $$str =~ s/\x{42D}/Э/g;
  $$str =~ s/\x{42E}/Ю/g;
  $$str =~ s/\x{42F}/Я/g;
  $$str =~ s/\x{430}/а/g;
  $$str =~ s/\x{431}/б/g;
  $$str =~ s/\x{432}/в/g;
  $$str =~ s/\x{433}/г/g;
  $$str =~ s/\x{434}/д/g;
  $$str =~ s/\x{435}/е/g;
  $$str =~ s/\x{451}/ё/g;
  $$str =~ s/\x{436}/ж/g;
  $$str =~ s/\x{437}/з/g;
  $$str =~ s/\x{438}/и/g;
  $$str =~ s/\x{439}/й/g;
  $$str =~ s/\x{43A}/к/g;
  $$str =~ s/\x{43B}/л/g;
  $$str =~ s/\x{43C}/м/g;
  $$str =~ s/\x{43D}/н/g;
  $$str =~ s/\x{43E}/о/g;
  $$str =~ s/\x{43F}/п/g;
  $$str =~ s/\x{440}/р/g;
  $$str =~ s/\x{441}/с/g;
  $$str =~ s/\x{442}/т/g;
  $$str =~ s/\x{443}/у/g;
  $$str =~ s/\x{444}/ф/g;
  $$str =~ s/\x{445}/х/g;
  $$str =~ s/\x{446}/ц/g;
  $$str =~ s/\x{447}/ч/g;
  $$str =~ s/\x{448}/ш/g;
  $$str =~ s/\x{449}/щ/g;
  $$str =~ s/\x{44A}/ъ/g;
  $$str =~ s/\x{44B}/ы/g;
  $$str =~ s/\x{44C}/ь/g;
  $$str =~ s/\x{44D}/э/g;
  $$str =~ s/\x{44E}/ю/g;
  $$str =~ s/\x{44F}/я/g;
}

Автор: sharq 14.2.2006, 11:08
nitr, попробуй то же самое сделать через tr и задание диапазона значений (значения у тебя ведь попорядку идут). smile

Зачем в ручную конвертировать, это же не транслит?
В perl 5.8.x - есть модуль Encode, который входит в стандартную поставку perl. (!)
В perl 5.6.x - можно используя дополнительные модули, например, cyrillic или Text::Iconv.

Всем советую переходить на perl 5.8.7 - последюю стабильную версию perl и использовать встроенные средства.

smile

Автор: nitr 14.2.2006, 12:28
=) Ему почему-то так не хотелось... И ещёё раз повторяюсь, на многих шеллах перл 5.004 и 5.005, и бывает урезаны модули, так что всё ОК думаю smile А это код я привёл как ещё один пример, выше до меня были уже... верные.

Автор: sharq 14.2.2006, 14:29
Цитата(nitr @ 14.2.2006, 13:28 Найти цитируемый пост)
И ещёё раз повторяюсь, на многих шеллах перл 5.004 и 5.005

к чертям такие шеллы!
Нормальная support-команда достаточно хорошо следит за своим программным обеспечением.


Автор: nitr 14.2.2006, 17:05
Я думаю, скорее про халявные говрил ;)

Автор: rcdimon 15.2.2006, 11:51
Цитата

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


Вот когда летом, наконец, поставлю на площадку свой севрер, вот тогда будте УВЕРЕНЫ! У меня стоит самый новый перл и модули, какие мне нужны smile)) А пока приходится просить админов ставить.. они сами далеки от перла. неохотно это делают

Автор: nitr 16.2.2006, 06:19
rcdimon, тож пригодиться:
Код

sub koi2win{
  my $str = shift;
  $str =~ tr/БВЧЗДЕЈЦЪЙКЛМНОПРТУФХЖИГЮЫЭЯЩШЬАСбвчздеіцъйклмнопртуфхжигюыэящшьас/абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ/;
  return $str;


sub translit{
   my $text = shift;
   $text =~ s/ё/e/g; $text =~ s/Ё/E/g; 
   $text =~ s/ж/zh/g; $text =~ s/Ж/ZH/g; 
   $text =~ s/х/h/g; $text =~ s/Х/H/g; 
   $text =~ s/ч/ch/g; $text =~ s/Ч/CH/g;
   $text =~ s/щ/sc/g; $text =~ s/Щ/SC/g; 
   $text =~ s/ш/sh/g; $text =~ s/Ш/SH/g; 
   $text =~ s/э/e/g; $text =~ s/Э/E/g; 
   $text =~ s/ю/ju/g; $text =~ s/Ю/JU/g; 
   $text =~ s/я/ja/g; $text =~ s/Я/JA/g; 

   $text =~ tr/абвгдезийклмнопрстуфцыьъ/abvgdezijklmnoprstufcy'`/;
   $text =~ tr/АБВГДЕЗИЙКЛМНОПРСТУФЦЫ/ABVGDEZIJKLMNOPRSTUFCY/;
   return $text;


Автор: rcdimon 21.2.2006, 16:50
Где Text::Iconv можно взять для PPM ?

Автор: sharq 21.2.2006, 17:25
rcdimon,
Цитата(rcdimon @ 21.2.2006, 17:50 Найти цитируемый пост)
Где Text::Iconv можно взять для PPM ?

http://theoryx5.uwinnipeg.ca/ppms/.

smile

Автор: rcdimon 24.2.2006, 13:44
Признаться честно- так и не нашел где же там его можно скачать.... smile

Автор: rcdimon 24.2.2006, 16:23
Все, нашел. Нужно было всего-то в Google.com набрать Text::Iconv ppd и перейти по первой ссылке smile


НО он не может мне помочь! Глюки какие-то!

Код

use Text::Iconv;
use XML::RSS;
use LWP::Simple;

my $conv = Text::Iconv->new("UTF-8", "WINDOWS-1251");

my $content =get('http://xxx.xx/xml.rss');

my $rss = new XML::RSS;
        $rss->parse($content);

foreach my $item (@{$rss->{'items'}}) {

my $ntitle        = $item->{title};
$ntitle =  $conv->convert( $ntitle );
print $ntitle; # Выдает что-то типа этого- Г‘åðèÿ ГўГЁГ¤ГҐГ®ГЄГ Г°ГІ Club 3D Radeon X1900
}



Выдает ужасную абракадабру!

Прошу еще раз обратить внимание- что коды символов, котрые выдает XML::RSS- ord() бывают больше тысячи!
Если взять просто строку в UTF-8 или считать ее из файла- то все отлично перекодируется. А вот из XML::RSS НИКАК! smile

Автор: nitr 24.2.2006, 17:07
Код

use Encode qw(from_to);

...
from_to($str, 'utf8', 'cp1251');
...

Автор: rcdimon 24.2.2006, 18:26
Этим я уже пользовался. И как раз, когда это мне не помогло, пошел эксперементировать с Text::Iconv

Автор: nitr 24.2.2006, 18:49
Код

use Unicode::Map();

my $map = Unicode::Map->new('CP1251');
...
$str = $map->from_unicode($str);
...


Вот экспериментируй smile http://search.cpan.org/~mschwartz/Unicode-Map-0.112/Map.pm

Автор: rcdimon 24.2.2006, 19:06
А что это за штука? При чем тут UTF-16?

Автор: rcdimon 26.2.2006, 00:37
Ужасные траблы с кодировкой именно в консоле! Когда программа запущена из под веба- то с кодировкой все ок!

А в консоле начиает глючить! на вставке в базу данных особенно.. совсем не понимаю в чем дело! помогите пожалуйста smile smile
Добавлено @ 00:38
Чем для программы на перл отличается запуск из консоли от запуска через веб?

Автор: nitr 26.2.2006, 00:45
Консоль.... KOI8-R =)))

Автор: rcdimon 26.2.2006, 09:27
Ну во первых не кои8 а cp866
а во вторых мне все равно надо сделать что бы все работало!

Я где-то видел какой-то маленький код, который изменяет кодиковку стандартного выходного потока! Можно указать свою! И это действительно работало! Но мне тогда это было не нужно и я потерял куда-то.... Кто нить знает че нить по этой теме?
Добавлено @ 09:31
В реальных условиях программа будет работать под Unix. Сейчас же для разработки я использую винду и денвер.

Автор: nitr 26.2.2006, 22:07
чего? у тебя не *nix сервер? Для меня это странно ;) Да и даже под виндой cp866, думаю глупо... А свой выходной поток просто в файл перенапрявь, вот и решение проблем!!! А так глупо... в консоле результат глядеть smile

Автор: rcdimon 26.2.2006, 22:13
Да я не в консоле его гляжу!

Я получаю данные, которые мне передает XML::RSS, перекодирую их из utf-8 в cp1251 и записываю в базу данных! И в базе такая мура!

Если в эту же базу пистаь через Perl программу, которая работает через веб- то все ок.

Код

чего? у тебя не *nix сервер?


В нормальных условиях программа будет работать под *nix, но при разработке я использую денвер!

Автор: nitr 26.2.2006, 22:35
Значит проверь БД... больше никто думаю нового не придумает, просто ещё добавять пяток новых способов, которые конкретно тебе, не ПОМОГУТ. На форуме поиск хороший, ищи всё что с кодировками БД, тем более недавно об этом говорилось... Читай внимательно! BlackLFL он отвечал на эти вопросы...

Автор: korob2001 26.2.2006, 22:39
так можешь перегнать cp1251 в cp866:
Код

sub win_to_dos {
    my $str = shift;
    $str =~ y/\300-\377\250\227/\200-\257\340-\361/;
    return $str;
}

smile Но мне кажется, что в данном случае тебе это не поможет, так как грабли скорее всего в кодировке базы, а не stdout
Для того, что бы проверить это, достаточно попробовать сохранить данные полученные из RSS в текстовый файл. Если там не увидешь абракадабры, то меняй кодировку БД.

Автор: nitr 26.2.2006, 22:48
Вот верно smile Я почти о том же говорил smile
Добавлено @ 22:50
О!, а можно из cp1251 ещё раз в cp1251 кодировать? smile Это вопрос

Автор: korob2001 26.2.2006, 22:57
Цитата(nitr @ 26.2.2006, 19:48 Найти цитируемый пост)
О!, а можно из cp1251 ещё раз в cp1251 кодировать?  Это вопрос

Угу smile
Код

s/(.)/$1/g;

Автор: nitr 26.2.2006, 23:02
=) а что делает вот этот код?
а обратно в utf?
Добавлено @ 23:02
для чего используют
Код
pack("U*", ...);
?

Автор: rcdimon 27.2.2006, 06:54
самое интересное вот в чем...

Что если подготовить SQL запрос в переменной, а потом записать его в файл, а потом считать из того же файла и отправить базе- то все ОК.

Код

$sql = "INSERT INTO " . $prefix . "_news
                (
                    rid,
                    ntitle,
                    link,
                    description,
                    pub_date,
                    webmaster,
                    unix_date,
                    pub_date_rss
                )
                VALUES
                (
                    '$hash->{rid}',
                    '$ntitle',
                    '$link',
                    '$desc',
                    '$te',
                    '$webmaster',
                    '$unix_pub_date',
                    '$pub_date'
                )";

                open (MF, ">4.txt");
                     print MF $sql;
                close (MF);
                open (MF, "4.txt");
                     @a = <MF>;
                close (MF);
                my $bb;
                $bb = '';
                    foreach(@a){
                        $bb .= $_;
                    }
                mysql_request_new ( $bb );

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)