Использование utf8 везде в / с Perl скриптом - PullRequest
0 голосов
/ 11 сентября 2018

Я использую последний Perl под немецкой Windows 7 и хочу использовать utf8 везде в моих программах perl (для скрипта, содержимого файла, имен файлов, почтовых текстов и т. Д.).

Всеработает нормально, но я сталкиваюсь с проблемами при попытке обработать файлы, имеющие специальные символы в имени файла.Даже system звонки не работают.Так (как) я могу сказать Perl использовать utf8 везде ?

Я пробовал некоторое время с encode и decode, но очень непонятно, почему это работает, как работает... Также мне нужно encode('cp850', TEXT) для правильного отображения в окне командной строки.

Примеры:

Когда мне нужно скопировать файл, он работает только при использовании File::copy(encode("iso-8859-1", $filename), ...)и когда я хочу работать с pdf-файлами, успешной командой является system(encode('cp850', sprintf('pdftk.exe %s...', decode('utf8', $file))));

Почему это (особенно декодирование в системном вызове) и есть ли более простой способ?Может быть, что-то с use open ':encoding...', но мне пока не повезло.

Ответы [ 3 ]

0 голосов
/ 12 сентября 2018

Поскольку пока нет подходящего поста для ответов, я постараюсь записать здесь рабочий образец.Надеюсь, однажды в нем больше не будет ошибок.До тех пор, пожалуйста, публикуйте свои предложения / решения, которые я протестирую и обновлю этот код в случае успеха.

В настоящее время нерешенные проблемы:

  • открытие файла PDF с помощью open
  • открытие файла PDF с помощью CAM::PDF->new
  • обработка файла PDF с помощью system вызов

test.pl:

$| = 1;
use strict;
use warnings;
use utf8;
use CAM::PDF;
use open ':std', ':encoding(UTF-8)';
BEGIN {
  if ($^O eq "MSWin32") {
    require Win32::Unicode::File;
    Win32::Unicode::File->import();
  }
}

my $file = 'Täst.pdf';
print "FILENAME: $file\n";

unlink("file2.pdf");
copyW($file, "file2.pdf") or print "cannot copy file: $!\n";

if (!open(FH, $file)) {
  print "cannot open file by open '$file': $!\n";
}
else {close FH}

my $pdf = CAM::PDF->new($file) or print "cannot open file by CAM::PDF: $!\n";
print "\n";

system("pdftk.exe $file cat 2 4 output out.pdf") or print "cannot run command: $!\n";
print "\n";

test.cmd:

Требуется установить шрифт "Lucida Console" для окна командной строки.

@echo off
chcp 65001 >nul
call perl.exe test.pl
chcp 850 >nul
pause

Вывод в Windows:

FILENAME: Täst.pdf

cannot open file by open 'Täst.pdf': No such file or directory

cannot open file by CAM::PDF: No such file or directory

Error: Unable to find file.
Error: Failed to open PDF file:
   Täst.pdf
Drücken Sie eine beliebige Taste . . .
0 голосов
/ 19 сентября 2018

Вот реальный, конкретный и определенный ответ того, кто только недавно прошел через эту проблему:

В Windows нельзя использовать Perl 5.28.0 или ниже, чтобы использовать UTF8 для всего.

Вот почему: Начиная с Perl 5.28.0, функции обработки файлов в ядре perl трагически для этого не нужны.Windows хранит имена файлов как (проще говоря) UTF16, а функции широких символов windows api возвращают имена файлов в виде широких символов, подобно тому, как Perl уже работает внутри.Однако при получении их из файловой системы ядро ​​perl преобразует их в байты в кодировке локальной системы.Наоборот при написании имен файлов.Итак, морально, у вас есть такой поток, перефразированный как Perl:

use utf8;

sub readdir_perl {
    my $dir = shift;
    my $fn = readdir $dir;
    $fn = encode $fn, CP_ACP;
    return $fn;
}

sub open_perl {
    my $fn = shift;
    $fn = decode $fn, CP_ACP;
    open my $FH, $fn;
    return $FH;
}

Два важных замечания:

  • Все вышеперечисленное перефразировано.Это примерно то, как ядро ​​Perl реализует эти функции в C, и вы не можете их ни менять, ни CP_ACP бесполезно на время выполнения программы.
  • Преобразование из широких символов в CP_ACP принудительно.Это не спасает от ошибок.Если есть широкие символы, которые нельзя представить с пользой, он преобразует их в символ ?, оставляя вас с кучкой мусора.

Тем не менее, что вы можете сделать?

  1. Использование Win32 :: LongPath .Он обрабатывает большую часть того, что вам нужно внутри.Для файлов.Имейте в виду, что он надежно работает только на томах, для которых настроены короткие пути, обычно это C: и ничего больше.Используйте system как обычно, но убедитесь, что вы рассматриваете все как байты и декодируете / кодируете соответственно.Существует пример кода .Вам также нужно будет внедрить обработку всех файлов вручную, и вы не сможете использовать другой код, чтобы использовать функции LongPath.
  2. Дождитесь исправления ядра perl.Насколько я знаю, в настоящее время нет никаких планов сделать это в ближайшее время, так как любое простое исправление может сломать устаревшие сценарии, которые полагаются на преобразование UTF16 в системную кодовую страницу, чтобы с пользой переходить в unicode umlauts в немецкие системы и т. Д..
  3. Используйте другой язык.Может быть, PowerShell.
0 голосов
/ 11 сентября 2018

Сначала установите для кодовой страницы вашей командной строки значение 65001

chcp 65001

Это позволит вам использовать и отображать символы utf8 в командной строке.Имена файлов зависят от используемой файловой системы.NTFS хранит имена файлов в кодировке UTF-16LE.См. этот вопрос о том, как создавать и получать доступ к файлам с именами файлов Unicode в Windows.

Команды System () должны быть закодированы в той же кодовой странице, что и командная строка, поэтому после выполнения chcp 65001 вы можете закодировать команду system() в utf8

...