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


Автор: mastercz 2.9.2009, 05:34
Подскажите пожалуйста.
Вот решил использовать в качестве конвертера Encode вместо Iconv, потому что так и не смог заставить Iconv игнорировать ошибочные символы.
Однако при конвертации из utf-8 в koi8-r с помошью  from_to($string, "utf-8", "koi8-r"); 
получаю ошибку:  Cannot decode string with wide characters  ...
Если я указываю:  utf8_off($string);
, то конвертация происходит правильно. В документации написанно что этот влаг использовать нехороше.

Конвертирую хэшь массив. 
Как сделать конверсию правильно. заранее благодарю за ответ.

Автор: amg 2.9.2009, 06:12
А попробуйте 
from_to($string, "utf8", "koi8-r");
(utf8 без дефиса). Я вовсе не уверен, но вдруг поможет.

Автор: mastercz 2.9.2009, 08:16
Не получаеться, к сожалению.
Ругаеться : Cannot decode string with wide characters at ...
Вот пример: 
Код

<root xmlns:sql="urn:schemas-microsoft-com:xml-sql">
  
  <row ID="24F68470-8787-4780-93B6-DBDAA07FC2FC"  Parameter="2" Date="30.11.2006" DateText="Привет Мир!!!" />
</root>

Код

#!/usr/bin/perl -w
use My::Encode;
use Data::Dumper;
use XML::Simple;

#my $Test;
# $Test->{row}->{DateText}="ПРИВЕТ МИР"; 

#my $xs = XML::Simple->new(ForceArray => 1, KeepRoot => 1);
#my $Test = XMLin('set.xml');

    print Dumper($Test)."\n";

        my $conv = My::Encode->new("utf8","koi8-r");
    my $ZZ=$conv->convert($Test->{row}->{DateText});
    print "-->>".$ZZ."\n";



запись  
Код

my $conv = My::Encode->new("utf8","koi8-r"); $conv->convert($Test->{row}->{DateText}); 

аналогична 
Код

 from_to($string, "utf8", "koi8-r");

нестал в примере переделывать ....
Так вот если беру хэш из XML то: Cannot decode string with wide characters at /usr/lib....
Если сроздаю хэш внутри файла 
Код

#my $Test;
# $Test->{row}->{DateText}="ПРИВЕТ МИР"; 

то все работает.

Автор: arto 2.9.2009, 08:59
это вам надо разбираться с XML::Simple, он перекодирует внутри себя в utf8, возможно не выставляя utf8_on у строки.

Автор: ginnie 2.9.2009, 09:17
mastercz, покажите результат 
Код

Devel::Peek::Dump($string); # функция отобразит содержимое переменной и флаги

до перекодировки $string.

Автор: mastercz 3.9.2009, 01:20
2->arto
В том-то и дело, что как я говорил в первом посте с принудительным  utf8_off($string); проблем не возникает.
2->ginnie
Вот результат Devel::Peek::Dump($string); :

SV = RV(0x875846c) at 0x874c9f8
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,ROK)
  RV = 0x89773a8
  SV = PVHV(0x88bb458) at 0x89773a8
    REFCNT = 1
    FLAGS = (SHAREKEYS,HASKFLAGS)
    UV = 2
    NV = 0
    ARRAY = 0x8960080  (0:6, 1:2)
    hash quality = 125.0%
    KEYS = 2
    FILL = 2
    MAX = 7
    RITER = -1
    EITER = 0x0
    Elt "xmlns:sql" [UTF8 "xmlns:sql"] HASH = 0xf73e3669
    SV = PV(0x89733fc) at 0x89773b4
      REFCNT = 1
      FLAGS = (POK,pPOK,UTF8)
      PV = 0x8972f00 "urn:schemas-microsoft-com:xml-sql"\0 [UTF8 "urn:schemas-microsoft-com:xml-sql"]
      CUR = 33
      LEN = 34
    Elt "row" [UTF8 "row"] HASH = 0x2f64eb8b
    SV = PV(0x8973438) at 0x89b0c88
      REFCNT = 1
      FLAGS = (ROK)
      RV = 0x8977474
      SV = PVHV(0x88bb488) at 0x8977474
        REFCNT = 1
        FLAGS = (SHAREKEYS,HASKFLAGS)
        UV = 4
        NV = 0
        ARRAY = 0x896ae68  (0:5, 1:2, 2:1)
        hash quality = 91.7%
        KEYS = 4
        FILL = 3
        MAX = 7
        RITER = -1
        EITER = 0x0
        Elt "ID" [UTF8 "ID"] HASH = 0x9d86e860
        SV = PV(0x895829c) at 0x8977480
          REFCNT = 1
          FLAGS = (POK,pPOK,UTF8)
          PV = 0x895fd30 "24F68470-8787-4780-93B6-DBDAA07FC2FC"\0 [UTF8 "24F68470-8787-4780-93B6-DBDAA07FC2FC"]
          CUR = 36
          LEN = 37
      PV = 0x8977474 ""
      CUR = 0
      LEN = 0

Автор: ginnie 3.9.2009, 10:01
mastercz, я всегда считал, что $string должен быть скаляром, а не ссылкой на хэш, как у Вас.

Воспроизвел Вашу ошибку:

Код

perl -MEncode -e 'my $string = "тест"; $string = Encode::decode("cp1251", $string); Encode::from_to($string, "utf8", "cp1251"); print $string, $/;'


корректный вариант такой 

Код

perl -MEncode -e 'my $string = "тест"; $string = Encode::decode("cp1251", $string); $string = Encode::encode("cp1251", $string); print $string, $/;'


т.е. Вам надо использовать 

Код

$string = Encode::encode("koi8-r", $string);

Автор: mastercz 4.9.2009, 04:12
ginnie, благодарю за помошь.

Оказывается я еще не понимал как работает этот преобразователь, так как (видимо по скудоумию) не читаю man по модулю.
Если я теперь правильно понимаю decode - преобразует из выбраной кодировки в utf8, соответственно encode делает обратно?

Благодаря твоей подсказке, все работает.

Правда, меня слегка смутила фраза 
Цитата

  mastercz, я всегда считал, что $string должен быть скаляром, а не ссылкой на хэш, как у Вас.

как я понимаю:
Код

perl -MEncode -e 'my $var; $var->{level0}->{level1}="Привет Мир!!"; print ref(\$var->{level0}->{level1');$/;'

Выдает SCALAR.

Может быть я что-то не туда использую ? 

Автор: ginnie 4.9.2009, 11:39
mastercz, по поводу скаляра поясняю:

в первом сообщении написано from_to($string, "utf-8", "koi8-r");, из чего я сделал вывод, что $string - скаляр, поэтому попросил вывести его содержимое при помощи Devel::Peek::Dump(). Из содержимого я увидел, что $string не скаляр, а ссылка на хэш, и не может непосредственно использоваться в from_to($string, "utf-8", "koi8-r");.

По поводу utf8: сообщение "Cannot decode string with wide characters  ..." говорит о том, что мы пытаемся в функцию from_to() передать не последовательность байтов, а строку unicode-символов (т.е. с установленным флагом utf8). Для преобразования unicode-символов удобнее всего использовать функцию encode().
Разобраться с unicode в Perl непросто, я тоже постоянно испытываю трудности, приходится периодически перечитывать perldoc perluniintro и описание модуля Encode.

Автор: mastercz 7.9.2009, 02:10
Извиняюсь за еще один глупый вопрос, но возможно ли Encode научить работать с ошибочным символом ? Скажем если в koi8-r encode находить символ, которого нет в стандарте, то он его ищет ...мммм ну где нибудь еще-где его может определить пользователь с указанием во что его нужно преобразовывать? 
Что-то типа koi8-r если нашелся символ chr("185") то заменить его на символ № (в кодировке cp1251).

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