Знатоки Perl-а, помогите плз: нужен автономный код для конвертации utf-8 -> windows-1251

Знатоки Perl-а, помогите плз: нужен автономный код для конвертации строки utf-8 -> windows-1251

В идеале - на Perl-е, но сгодится и C или ещё что-нибудь, что можно переписать на Perl-е. Главное, чтобы код был автономный, а не ссылался на библиотеки или модули. Потому что перловый модуль Unicode::Map8 я никак не могу заставить работать на своей системе... :((
---------------------
Update: Проблема решена: http://lib.rus.ec/node/110648#comment-19447

Комментарии

Text::Iconv?

Fix написал:
Text::Iconv?

Он, ЕЯПП, просто интерфейс к библиотеке iconv, а я очень сомневаюсь что она у меня есть. Да я даже сам этот Text::Iconv инсталлировать вряд ли смогу. Если б мог - добился бы работы от Unicode::Map8 :((

На всяк слу, вот конфигурация моего перла:

E:\>perl -V
Summary of my perl5 (revision 5 version 8 subversion 7) configuration:
  Platform:
    osname=MSWin32, osvers=5.0, archname=MSWin32-x86-multi-thread
    uname=''
    config_args='undef'
    hint=recommended, useposix=true, d_sigaction=undef
    usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=undef uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cl', ccflags ='-nologo -Gf -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_STRICT -DHAVE_DES_FCRYPT -DBUILT_BY_ACTIVESTATE -DNO_HASH_SEED -DUSE_SITECUSTOMIZE -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -DPERL_MSVCRT_READFIX',
    optimize='-MD -Zi -DNDEBUG -O1',
    cppflags='-DWIN32'
    ccversion='12.00.8804', gccversion='', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=10
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='__int64', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='link', ldflags ='-nologo -nodefaultlib -debug -opt:ref,icf  -libpath:"C:\Perl\lib\CORE"  -machine:x86'
    libpth=\lib
    libs=  oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib  comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib  netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib  version.lib odbc32.lib odbccp32.lib msvcrt.lib
    perllibs=  oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib  comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib  netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib  version.lib odbc32.lib odbccp32.lib msvcrt.lib
    libc=msvcrt.lib, so=dll, useshrplib=yes, libperl=perl58.lib
    gnulibc_version='undef'
  Dynamic Linking:
    dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' '
    cccdlflags=' ', lddlflags='-dll -nologo -nodefaultlib -debug -opt:ref,icf  -libpath:"C:\Perl\lib\CORE"  -machine:x86'


Characteristics of this binary (from libperl):
  Compile-time options: MULTIPLICITY USE_ITHREADS USE_LARGE_FILES
                        USE_SITECUSTOMIZE PERL_IMPLICIT_CONTEXT
                        PERL_IMPLICIT_SYS
  Locally applied patches:
        ActivePerl Build 813 [148120]
        Iin_load_module moved for compatibility with build 806
        PerlEx hacks for CGI::Carp
        Less verbose ExtUtils::Install and Pod::Find
        instmodsh upgraded from ExtUtils-MakeMaker-6.25
        24699 ICMP_UNREACHABLE handling in Net::Ping
        21540 Fix backward-compatibility issues in if.pm
  Built under MSWin32
  Compiled at Jun  6 2005 13:36:37
  @INC:
    C:/Perl/lib
    C:/Perl/site/lib
    .

E:\>

Если речь идет о *nix и надо сделать быстро, то может быть попробовать выполнить из perl recode(1)? А потом, на досуге, повоевать с Unicode::Map8...

Illarion написал:
Если речь идет о *nix и надо сделать быстро, то может быть попробовать выполнить из perl recode(1)? А потом, на досуге, повоевать с Unicode::Map8...

Машина - винбокс (Win XP Pro), причем не девелоперская, на ней даже make нету и я не все смогу инсталлировать (комп не мой, компании).

И задача - конвертить строку, не файл... хотя если бы был на машине recode, можно было бы сплюнуть строку в файл и напустить на него recode... но его нет.

Собственно, задача - вынуть (перловым скриптом) из ~140,000 fb2-файлов (кодировки windows-1251, windows-1252, utf-8, koi8-r, iso-8559-1) строку с названием книги и сравнить. Я могу управиться с windows-1251, windows-1252, koi8-r, iso-8559-1, но вот на utf-8 произошел затык, чтоб его...

Мейби так:

#!/usr/bin/perl
use open IN => ':utf8', OUT => ':encoding(cp1251)';
use open ':std';
print while(<>);

?

А ноги у этой хрени растут из модуля Encode.pm.

ground0 написал:
А ноги у этой хрени растут из модуля Encode.pm.

Так... кажется, в моем перле есть модуль Encode::Encoder -- Object Oriented Encoder... изучаю...

ground0 написал:
А ноги у этой хрени растут из модуля Encode.pm.

да-да-да
можно конвертнуть двумя способами:
use Encode qw(from_to encode decode);
$str = "привет";
from_to($str, "utf8", "cp1251");
print $str;
$str = "привет";
print encode("cp1251", decode("utf8", $str));

ground0 написал:
А ноги у этой хрени растут из модуля Encode.pm.

Кажись, заработало. Именно с использованием модуля Encode - спасибо, ground0!

Не обошлось без метода тыка и странностей, но вроде работает - кроме некоторых экзотических fb2-файлов, в которых указана кодировка iso-8859-1 или windows-1252, но буквы на самом деле содержатся в какой-то странной форме, типа HTML-символов, вот так:
&#1050;&#1091;&#1088;&#1089; &#1085;&#1072;

Если кому интересно - работает вот примерно такой код:

# NO!!! use encoding 'windows-1251';
# NO!!! use encoding 'utf-8';
use Encode;

...
        my $tit    = &sub_fb2_get_booktitle($des);
        my $enc    = &sub_fb2_get_encoding($des);
        # nope... binmode(STDOUT,":utf8");
        if( uc($enc) eq "WINDOWS-1252")
        {
            $tit = decode("iso-8859-2",$tit);
        }elsif( uc($enc) eq "WINDOWS-1251" ){
            $tit = decode("windows-1251",$tit);
        }elsif( uc($enc) eq "ISO-8859-1" ){
            $tit = decode("iso-8859-1",$tit);
        }elsif( uc($enc) eq "KOI8-R" ){
            $tit = decode("koi8-r",$tit);
        }elsif( uc($enc) eq "UTF-8" ){
            $tit = decode("utf-8",$tit); # yes, it's necessary!
        }else{
            printf("[%6d of %6d] Bad enc="%s" $fullfname_G\n",$curnum_G,$listsize_G,$enc);
        }; # iffelse        
        ###
        # Works!!!
        $tit = encode("windows-1251",$tit);
        # Now tit is in win-1251

А можно на php? В прошлом веке я с такими проблемами часто сталкивался
тупое сопоставление

<?php
$_utf8win1251
= array(
"\xD0\x90"=>"\xC0","\xD0\x91"=>"\xC1","\xD0\x92"=>"\xC2","\xD0\x93"=>"\xC3","\xD0\x94"=>"\xC4",
"\xD0\x95"=>"\xC5","\xD0\x81"=>"\xA8","\xD0\x96"=>"\xC6","\xD0\x97"=>"\xC7","\xD0\x98"=>"\xC8",
"\xD0\x99"=>"\xC9","\xD0\x9A"=>"\xCA","\xD0\x9B"=>"\xCB","\xD0\x9C"=>"\xCC","\xD0\x9D"=>"\xCD",
"\xD0\x9E"=>"\xCE","\xD0\x9F"=>"\xCF","\xD0\xA0"=>"\xD0","\xD0\xA1"=>"\xD1","\xD0\xA2"=>"\xD2",
"\xD0\xA3"=>"\xD3","\xD0\xA4"=>"\xD4","\xD0\xA5"=>"\xD5","\xD0\xA6"=>"\xD6","\xD0\xA7"=>"\xD7",
"\xD0\xA8"=>"\xD8","\xD0\xA9"=>"\xD9","\xD0\xAA"=>"\xDA","\xD0\xAB"=>"\xDB","\xD0\xAC"=>"\xDC",
"\xD0\xAD"=>"\xDD","\xD0\xAE"=>"\xDE","\xD0\xAF"=>"\xDF","\xD0\x87"=>"\xAF","\xD0\x86"=>"\xB2",
"\xD0\x84"=>"\xAA","\xD0\x8E"=>"\xA1","\xD0\xB0"=>"\xE0","\xD0\xB1"=>"\xE1","\xD0\xB2"=>"\xE2",
"\xD0\xB3"=>"\xE3","\xD0\xB4"=>"\xE4","\xD0\xB5"=>"\xE5","\xD1\x91"=>"\xB8","\xD0\xB6"=>"\xE6",
"\xD0\xB7"=>"\xE7","\xD0\xB8"=>"\xE8","\xD0\xB9"=>"\xE9","\xD0\xBA"=>"\xEA","\xD0\xBB"=>"\xEB",
"\xD0\xBC"=>"\xEC","\xD0\xBD"=>"\xED","\xD0\xBE"=>"\xEE","\xD0\xBF"=>"\xEF","\xD1\x80"=>"\xF0",
"\xD1\x81"=>"\xF1","\xD1\x82"=>"\xF2","\xD1\x83"=>"\xF3","\xD1\x84"=>"\xF4","\xD1\x85"=>"\xF5",
"\xD1\x86"=>"\xF6","\xD1\x87"=>"\xF7","\xD1\x88"=>"\xF8","\xD1\x89"=>"\xF9","\xD1\x8A"=>"\xFA",
"\xD1\x8B"=>"\xFB","\xD1\x8C"=>"\xFC","\xD1\x8D"=>"\xFD","\xD1\x8E"=>"\xFE","\xD1\x8F"=>"\xFF",
"\xD1\x96"=>"\xB3","\xD1\x97"=>"\xBF","\xD1\x94"=>"\xBA","\xD1\x9E"=>"\xA2");
function
utf8_win1251($a) {
    global
$_utf8win1251;
    if (
is_array($a)){
        foreach (
$a as $k => $v) {
            if (
is_array($v)) {
               
$a[$k] = utf8_win1251($v);
            } else {
               
$a[$k] = strtr($v, $_utf8win1251);
            }
        }
        return
$a;
    } else {
        return
strtr($a, $_utf8win1251);
    }
}
?>

острое сопоставление
<?php
function utfToWin($str){
      
$newstr = "";
      
$len=strlen($str);
      
$offset = 13264;
       for(
$a=0;$a<$len;$a++){
           if(
ord($str[$a])>128){
                   
$mord = (ord($str[$a+0])*64+ord($str[$a+1]))-$offset;
                      if(
$mord==177) $mord = ord('Ё');
                      if(
$mord==257) $mord = ord('е');
                   
$newstr .= chr($mord);
          
$a++;
           }else{
                
$newstr .= $str[$a];
           }
       }

       return
$newstr;
}
?>

gwarlock написал:
А можно на php?

Ааагромадное спасибо! Переделал под Перл Ваше "острое сопоставление" - работает, саб-бака! :)) По крайней мере на тестовых двадцати файликах - работает как лялечка.

У меня, конечно, есть подозрение что где-то может и сбойнуть (я правильно понимаю, что код предполагает все utf-8 буквы двухбайтными?) но это уже поодиночке разбираться будем. Ща я его на все 100+ тысяч напущу, пусть поурчит и посмотрим что скажет...

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

Зато модуль Encode, кажется, работает.

Питоновый код я тут где-то уже приводил

X