Вопрос о кодировке пути - PullRequest
       25

Вопрос о кодировке пути

4 голосов
/ 25 сентября 2011

Что я сделал, чтобы получить такую ​​странную кодировку в этом пути?
В моем файловом менеджере (Dolphin) имя пути выглядит хорошо.

#!/usr/local/bin/perl
use warnings;
use 5.014;
use utf8;
use open qw( :encoding(UTF-8) :std );
use File::Find;
use Devel::Peek;
use Encode qw(decode);

my $string;
find( sub { $string = $File::Find::name }, 'Delibes, Léo' );
$string =~ s|Delibes,\ ||;
$string =~ s|\..*\z||;
my ( $s1, $s2 ) = split m|/|, $string, 2;

say Dump $s1;
say Dump $s2;

# SV = PV(0x824b50) at 0x9346d8
#   REFCNT = 1
#   FLAGS = (PADMY,POK,pPOK,UTF8)
#   PV = 0x93da30 "L\303\251o"\0 [UTF8 "L\x{e9}o"]
#   CUR = 4
#   LEN = 16

# SV = PV(0x7a7150) at 0x934c30
#   REFCNT = 1
#   FLAGS = (PADMY,POK,pPOK,UTF8)
#   PV = 0x7781e0 "Lakm\303\203\302\251"\0 [UTF8 "Lakm\x{c3}\x{a9}"]
#   CUR = 8
#   LEN = 16

say $s1;
say $s2;

# Léo
# Lakmé

$s1 = decode( 'utf-8', $s1 );
$s2 = decode( 'utf-8', $s2 );

say $s1;
say $s2;

# L�o
# Lakmé

Ответы [ 2 ]

13 голосов
/ 25 сентября 2011

К сожалению, API путей к вашей операционной системе - это еще один «двоичный интерфейс», в котором вам придется использовать Encode::encode и Encode::decode для получения предсказуемых результатов.

Большинство операционных систем обрабатывают имена путей как последовательность октетов (т.е. байты).Решение о том, следует ли интерпретировать эту последовательность как латинское-1, UTF-8 или другое кодирование символов.Следовательно, значение, возвращаемое readdir(), является просто последовательностью октетов, и File::Find не знает, что вы хотите указать путь в качестве кодовых точек Unicode.Он формирует $File::Find::name, просто конкатенируя путь к каталогу (который вы указали) со значением, возвращаемым вашей ОС через readdir(), и таким образом вы получаете кодовые точки, смешанные с октетами.

Правило большого пальца: всякий раз, когдапередавая имена путей в ОС, Encode::encode() это, чтобы убедиться, что это последовательность октетов.При получении имени пути из ОС, Encode::decode() оно соответствует набору символов, в котором оно требуется вашему приложению.

Вы можете заставить свою программу работать, вызывая find следующим образом:

find( sub { ... }, Encode::encode('utf8', 'Delibes, Léo') );

А затем вызывать Encode::decode() при использовании значения $File::Find::name:

my $path = Encode::decode('utf8', $File::Find::name);

Чтобы быть более понятным, вот как $File::Find::name было сформировано:

use Encode;

# This is a way to get $dir to be represented as a UTF-8 string

my $dir = 'L' .chr(233).'o'.chr(256);
chop $dir;

say "dir: ", d($dir); # length = 3

# This is what readdir() is returning:

my $leaf = encode('utf8', 'Lakem' . chr(233));

say "leaf: ", d($leaf); # length = 7

$File::Find::name = $dir . '/' . $leaf;

say "File::Find::name: ", d($File::Find::name);

sub d {
  join(' ', map { sprintf("%02X", ord($_)) } split('', $_[0]))
}
0 голосов
/ 19 октября 2011

API файловой системы POSIX не работает, поскольку кодирование не применяется. Период.

Может возникнуть много проблем. Например, имя пути может даже содержать как latin1, так и UTF-8, в зависимости от того, как различные файловые системы в пути обрабатывают кодировку (и если они делают).

...