Как я могу открыть файл Unicode с Perl? - PullRequest
10 голосов
/ 17 марта 2010

Я использую osql для запуска нескольких сценариев sql для базы данных, а затем мне нужно просмотреть файл результатов, чтобы проверить, не произошло ли каких-либо ошибок. Проблема в том, что Perl не нравится тот факт, что файлы результатов имеют Unicode.

Я написал небольшой тестовый скрипт, чтобы проверить его, и вывод получился искаженным:

$file = shift;

open OUTPUT, $file or die "Can't open $file: $!\n";
while (<OUTPUT>) {
    print $_;
    if (/Invalid|invalid|Cannot|cannot/) {
        push(@invalids, $file);
        print "invalid file - $inputfile - schedule for retry\n";
        last;
    }            
}

Есть идеи? Я пытался декодировать, используя decode_utf8, но это не имеет значения. Я также пытался установить кодировку при открытии файла.

Я думаю, что проблема может заключаться в том, что osql помещает файл результатов в формат UTF-16, но я не уверен. Когда я открываю файл в textpad, он просто говорит мне «Юникод».

Редактировать: Использование Perl v5.8.8 Изменить: шестнадцатеричный дамп:

file name: Admin_CI.User.sql.results
mime type: 

0000-0010:  ff fe 31 00-3e 00 20 00-32 00 3e 00-20 00 4d 00  ..1.>... 2.>...M.
0000-0020:  73 00 67 00-20 00 31 00-35 00 30 00-30 00 37 00  s.g...1. 5.0.0.7.
0000-0030:  2c 00 20 00-4c 00 65 00-76 00 65 00-6c 00 20 00  ,...L.e. v.e.l...
0000-0032:  31 00                                            1.

Ответы [ 4 ]

16 голосов
/ 17 марта 2010

Файл предположительно имеет формат UCS2-LE (или UTF-16 ).

C:\Temp> notepad test.txt

C:\Temp> xxd test.txt
0000000: fffe 5400 6800 6900 7300 2000 6900 7300  ..T.h.i.s. .i.s.
0000010: 2000 6100 2000 6600 6900 6c00 6500 2e00   .a. .f.i.l.e...

При открытии такого файла для чтения необходимо указать кодировку:

#!/usr/bin/perl

use strict; use warnings;

my ($infile) = @ARGV;

open my $in, '<:encoding(UCS-2le)', $infile
    or die "Cannot open '$infile': $!";

Обратите внимание, что fffe в начале - это BOM .

9 голосов
/ 17 марта 2010

Ответ в документации для open , который также указывает на perluniintro . :)

open my $fh, '<:encoding(UTF-16LE)', $file or die ...;

Вы можете получить список имен кодировок, которые поддерживает perl:

% perl -MEncode -le "print for Encode->encodings(':all')"

После этого вам остается выяснить, какова кодировка файла. Это аналогично открытию любого файла с кодировкой, отличной от кодировки по умолчанию, независимо от того, определена ли она Юникодом или нет.

У нас есть глава в Эффективное программирование на Perl , в которой подробно рассматриваются.

5 голосов
/ 17 марта 2010

Попробуйте открыть файл с указанным слоем ввода-вывода, например, :

open OUTPUT,  "<:encoding(UTF-8)", $file or die "Can't open $file: $!\n";

Подробнее об этом см. perldoc open .

0 голосов
/ 29 апреля 2017
    #
    # -----------------------------------------------------------------------------
    # Reads a file returns a sting , if second param is utf8 returns utf8 string
    # usage:
    # ( $ret , $msg , $str_file )
    #         = $objFileHandler->doReadFileReturnString ( $file , 'utf8' ) ;
    # or
    # ( $ret , $msg , $str_file )
    #         = $objFileHandler->doReadFileReturnString ( $file ) ;
    # -----------------------------------------------------------------------------
    sub doReadFileReturnString {

        my $self      = shift;
        my $file      = shift;
        my $mode      = shift ;

        my $msg        = {} ;
        my $ret        = 1 ;
        my $s          = q{} ;

        $msg = " the file : $file does not exist !!!" ;
        cluck ( $msg ) unless -e $file ;

        $msg = " the file : $file is not actually a file !!!" ;
        cluck ( $msg ) unless -f $file ;

        $msg = " the file : $file is not readable !!!" ;
        cluck ( $msg ) unless -r $file ;

        $msg .= "can not read the file $file !!!";

        return ( $ret , "$msg ::: $! !!!" , undef )
            unless ((-e $file) && (-f $file) && (-r $file));

        $msg = '' ;

        $s = eval {
             my $string = ();    #slurp the file
             {
                local $/ = undef;

                if ( defined ( $mode ) && $mode eq 'utf8' ) {
                    open FILE, "<:utf8", "$file "
                      or cluck("failed to open \$file $file : $!");
                    $string = <FILE> ;
                    die "did not find utf8 string in file: $file"
                        unless utf8::valid ( $string ) ;
                }
                else {
                    open FILE, "$file "
                      or cluck "failed to open \$file $file : $!" ;
                    $string = <FILE> ;
                }
                close FILE;

             }
            $string ;
         };

         if ( $@ ) {
            $msg = $! . " " . $@ ;
            $ret = 1 ;
            $s = undef ;
         } else {
            $ret = 0 ; $msg = "ok for read file: $file" ;
         }
         return ( $ret , $msg , $s ) ;
    }
    #eof sub doReadFileReturnString
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...