Ricerca…


Osservazioni

Un avviso sulla codifica del nome file


Vale la pena ricordare che Codename non è solo specifico per la piattaforma, ma anche specifico per il filesystem .

Non è mai del tutto sicuro assumere (ma spesso lo è di solito) solo perché puoi codificare e scrivere su un determinato nome di file, che quando proverai ad aprire lo stesso nome di file per la lettura, verrà comunque chiamato la stessa cosa.

Ad esempio, se scrivi su un filesystem come FAT16 che non supporta l'unicode, i tuoi nomi file potrebbero essere tradotti silenziosamente in moduli compatibili ASCII.

Ma è anche meno sicuro presumere che un file che è possibile creare, leggere e scrivere con un nome esplicito verrà chiamato la stessa cosa quando interrogato tramite altre chiamate, ad esempio, readdir potrebbe restituire byte diversi per il nome del file rispetto a quello specificato per open .

Su alcuni sistemi come VAX, non si può nemmeno presumere che readdir restituirà lo stesso nome di file che hai specificato con open per i nomi di file semplice come foo.bar , perché le estensioni dei nomi dei file possono essere alterate dal sistema operativo.

Inoltre, in UNIX, esiste un insieme molto liberale di caratteri legali per i nomi di file consentiti dal sistema operativo, escludendo solo / e \0 , dove come su Windows, ci sono gamme specifiche di caratteri proibite nei nomi di file e causano errori.

Esercitare molta cautela qui, evitare trucchi di fantasia con i nomi dei file, se avete una scelta, e hanno sempre i test per assicurarsi che eventuali trucchi di fantasia che si fanno uso sono coerenti.

Esercita doppiamente la massima cautela se stai scrivendo codice destinato a essere eseguito su piattaforme esterne al tuo controllo, ad esempio se stai scrivendo un codice destinato a CPAN e presumi che almeno il 5% della tua base di utenti rimarrà bloccato utilizzando alcuni tecnologia antica o rotta, per scelta, per caso, o per poteri al di fuori del loro controllo, e che questi cospireranno per creare bug per loro.

: encoding (utf8) vs: utf8


Poiché UTF-8 è uno dei formati interni per la rappresentazione di stringhe in Perl, la fase di codifica / decodifica può essere saltata spesso. Invece di :encoding(utf-8) , puoi semplicemente usare :utf8 , se i tuoi dati sono già in UTF-8. :utf8 può essere usato tranquillamente con i flussi di output, mentre per il flusso di input può essere pericoloso, perché causa incoerenze interne quando si hanno sequenze di byte non valide. Inoltre, l'utilizzo di :utf8 per l'input può causare violazioni della sicurezza, quindi è consigliabile l'uso di :encoding(utf-8) .

Maggiori dettagli: Qual è la differenza tra: codifica e: utf8

UTF-8 vs utf8 contro UTF8


A partire da Perl v5.8.7 , "UTF-8" (con trattino) significa UTF-8 nella sua forma rigorosa e v5.8.7 sicurezza, mentre "utf8" significa UTF-8 nella sua forma liberale e libera.

Ad esempio, "utf8" può essere utilizzato per i punti di codice che non esistono in Unicode, come 0xFFFFFFFF . Corrispondentemente, sequenze di byte UTF-8 non valide come "\x{FE}\x{83}\x{BF}\x{BF}\x{BF}\x{BF}\x{BF}" verranno decodificate in un Unicode non valido (ma valido Perl) codepoint ( 0xFFFFFFFF ) quando si utilizza "utf8" , mentre la codifica "UTF-8" non consente la decodifica ai codepoints al di fuori dell'intervallo di Unicode valido e invece fornirebbe un carattere di sostituzione ( 0xFFFD ).

Poiché i nomi di codifica sono case insensitive, "UTF8" è uguale a "utf8" (cioè variante non rigida ).

Maggiori dettagli: UTF-8 contro utf8 contro UTF8

Più lettura


I dettagli sulla gestione Unicode di Perl sono descritti in maggior dettaglio nelle seguenti fonti:

Messaggi da stackoverflow.com (avvertenza: potrebbe non essere aggiornato):

Video di Youtube:

Crea nomi di file

I seguenti esempi utilizzano la codifica UTF-8 per rappresentare nomi di file (e nomi di directory) su disco. Se vuoi usare un'altra codifica, dovresti usare Encode::encode(...) .

use v5.14;
# Make Perl recognize UTF-8 encoded characters in literal strings.
# For this to work: Make sure your text-editor is using UTF-8, so
# that bytes on disk are really UTF-8 encoded.
use utf8;

# Ensure that possible error messages printed to screen are converted to UTF-8.
# For this to work: Check that your terminal emulator is using UTF-8.
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
    
my $filename = 'æ€'; # $filename is now an internally UTF-8 encoded string. 

# Note: in the following it is assumed that $filename has the internal UTF-8
#  flag set, if $filename is pure ASCII, it will also work since its encoding
#  overlaps with UTF-8. However, if it has another encoding like extended ASCII,
#  $filename will be written with that encoding and not UTF-8. 
# Note: it is not necessary to encode $filename as UTF-8 here
#  since Perl is using UTF-8 as its internal encoding of $filename already

# Example1  -- using open()
open ( my $fh, '>', $filename ) or die "Could not open '$filename': $!";
close $fh;

# Example2 -- using qx() and touch
qx{touch $filename};

# Example3 -- using system() and touch
system 'touch', $filename;

# Example4 -- using File::Touch
use File::Touch;
eval { touch( $filename ) }; die "Could not create file '$filename': $!" if $@;

Leggi i nomi dei file

Perl non tenta di decodificare i nomi di file restituiti da funzioni o moduli incorporati. Tali stringhe che rappresentano nomi di file devono sempre essere decodificate esplicitamente, in modo che Perl le riconosca come Unicode.

use v5.14;
use Encode qw(decode_utf8);

# Ensure that possible error messages printed to screen are converted to UTF-8.
# For this to work: Check that you terminal emulator is using UTF-8.
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

# Example1  -- using readdir()
my $dir = '.';
opendir(my $dh, $dir) or die "Could not open directory '$dir': $!";
while (my $filename = decode_utf8(readdir $dh)) {
    # Do something with $filename
}
close $dh;

# Example2  -- using getcwd()
use Cwd qw(getcwd);
my $dir = decode_utf8( getcwd() );

# Example3  -- using abs2rel()
use File::Spec;
use utf8;
my $base = 'ø';
my $path = "$base/b/æ";
my $relpath = decode_utf8( File::Spec->abs2rel( $path, $base ) );
# Note: If you omit $base, you need to encode $path first:
use Encode qw(encode_utf8);
my $relpath = decode_utf8( File::Spec->abs2rel( encode_utf8( $path ) ) );

# Example4  -- using File::Find::Rule (part1 matching a filename)
use File::Find::Rule;
use utf8;
use Encode qw(encode_utf8);
my $filename = 'æ';
# File::Find::Rule needs $filename to be encoded
my @files = File::Find::Rule->new->name( encode_utf8($filename) )->in('.');
$_ = decode_utf8( $_ ) for @files;

# Example5  -- using File::Find::Rule (part2 matching a regular expression)
use File::Find::Rule;
use utf8;
my $pat = '[æ].$'; # Unicode pattern
# Note: In this case:  File::Find::Rule->new->name( qr/$pat/ )->in('.')
#  will not work since $pat is Unicode and filenames are bytes
#  Also encoding $pat first will not work correctly
my @files;
File::Find::Rule->new->exec( sub { wanted( $pat, \@files ) } )->in('.');
$_ = decode_utf8( $_ ) for @files;
sub wanted {
    my ( $pat, $files ) = @_;
    my $name = decode_utf8( $_ );
    my $full_name = decode_utf8( $File::Find::name );
    push @$files, $full_name if $name =~ /$pat/;
}

Nota: se sei preoccupato per l'UTF-8 non valido nei nomi dei file, l'uso di decode_utf8( ... ) negli esempi precedenti dovrebbe probabilmente essere sostituito da decode( 'utf-8', ... ) . Questo perché decode_utf8( ... ) è un sinonimo di decode( 'utf8', ... ) e c'è una differenza tra le codifiche utf-8 e utf8 (vedi Note sotto per maggiori informazioni) dove utf-8 è più rigoroso su ciò che è accettabile di utf8 .

Interruttori a riga di comando per one-liner

Abilita prfma utf8

Per abilitare utf8 pragma in one-liner, l'interprete perl dovrebbe essere chiamato con -Mutf8 opzione -Mutf8 :

perl -Mutf8 -E 'my $人 = "human"; say $人'

Gestione Unicode con switch -C

Il flag della riga di comando -C ti consente di controllare le funzioni Unicode. Può essere seguito da un elenco di lettere di opzioni.

I / O standard

  • I - STDIN sarà in UTF-8
  • O - STDOUT sarà in UTF-8
  • E - STDERR sarà in UTF-8
  • S - abbreviazione di IOE , i flussi I / O standard saranno in UTF-8
echo "Ματαιότης ματαιοτήτων" | perl -CS -Mutf8 -nE 'say "ok" if /Ματαιότης/'

Argomenti dello script

  • A - considera @ARGV come una matrice di stringhe con codifica UTF-8
perl -CA -Mutf8 -E 'my $arg = shift; say "anteater" if $arg eq "муравьед"' муравьед

Livello PerlIO predefinito

  • i - UTF-8 è il livello PerlIO predefinito per i flussi di input
  • o - UTF-8 è il livello PerlIO predefinito per i flussi di output
  • D - stenografia di io
perl -CD -Mutf8 -e 'open my $fh, ">", "utf8.txt" or die $!; print $fh "개미 조심해"'

-M e -C possono essere combinati:

perl -CASD -Mutf8 -E 'say "Ματαιότης ματαιοτήτων\n"';

I / O standard

La codifica da utilizzare per i filehandle I / O standard ( STDIN , STDOUT e STDERR ), può essere impostata separatamente per ciascun handle utilizzando binmode :

binmode STDIN, ':encoding(utf-8)';
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

Nota: durante la lettura si preferisce in generale :encoding(utf-8) over :utf8 , vedere Note per ulteriori informazioni.

In alternativa, puoi usare il pragma open .

# Setup such that all subsequently opened input streams will use ':encoding(utf-8)'
# and all subsequently opened output streams will use ':utf8'
# by default
use open (IN => ':encoding(utf-8)', OUT => ':utf8');
# Make the (already opened) standard file handles inherit the setting 
# given by the IO settings for the open pragma
use open ( :std );
# Now, STDIN has been converted to ':encoding(utf-8)', and 
# STDOUT and STDERR have ':utf8'

In alternativa, per impostare tutti i filehandle (sia quelli ancora da aprire che quelli standard) da usare :encoding(utf-8) :

use open qw( :encoding(utf-8) :std );

Handle di file

Impostazione della codifica con open ()

Quando si apre un file di testo, è possibile specificare la codifica esplicita con un argomento a tre argomenti open() . Questo en / decoder collegato a un handle di file è chiamato "Livello I / O":

my $filename = '/path/to/file';
open my $fh, '<:encoding(utf-8)', $filename or die "Failed to open $filename: $!";

Vedi Note per una discussione delle differenze tra :utf8 e :encoding(utf-8) .

Impostazione della codifica con binmode ()

In alternativa, è possibile utilizzare binmode () per impostare la codifica per il singolo handle di file:

my $filename = '/path/to/file';
open my $fh, '<', $filename or die "Failed to open $filename: $!";
binmode $fh, ':encoding(utf-8)';

apri il pragma

Per evitare di impostare separatamente la codifica per ogni handle di file, è possibile utilizzare il pragma open per impostare un livello I / O predefinito utilizzato da tutte le chiamate successive alla funzione open() e operatori simili all'interno dello scope lessicale di questo pragma:

# Set input streams to ':encoding(utf-8)' and output streams to ':utf8'
use open (IN => ':encoding(utf-8)', OUT => ':utf8');
# Or to set all input and output streams to ':encoding(utf-8)'
use open ':encoding(utf-8)';

Impostazione della codifica con la riga di comando -C flag

Infine, è anche possibile eseguire l'interprete perl con un flag -CD che applica UTF-8 come livello I / O predefinito. Tuttavia, questa opzione dovrebbe essere evitata poiché si basa su un comportamento specifico dell'utente che non può essere previsto né controllato.

Il pragma utf8: usare Unicode nelle tue fonti

Il utf8 indica che il codice sorgente verrà interpretato come UTF-8. Ovviamente, questo funzionerà solo se il tuo editor di testo sta salvando anche la sorgente come codificata in UTF-8.

Ora, i valori letterali stringa possono contenere caratteri Unicode arbitrari; gli identificatori possono anche contenere Unicode ma solo caratteri di tipo word (vedi perldata e perlrecharclass per maggiori informazioni):

use utf8;
my $var1 = '§я§©😄';      # works fine
my $я = 4;                # works since я is a word (matches \w) character
my $p§2 = 3;              # does not work since § is not a word character.
say "ya" if $var1 =~ /я§/; # works fine (prints "ya")

Nota : quando si stampa del testo sul terminale, assicurarsi che supporti UTF-8. *

Potrebbero esserci relazioni complesse e controintuitive tra l'output e la codifica sorgente. Funzionando su un terminale UTF-8, potresti scoprire che l'aggiunta del utf8 sembra spezzare le cose:

$ perl -e 'print "Møøse\n"'
Møøse
$ perl -Mutf8 -e 'print "Møøse\n"'
M��se
$ perl -Mutf8 -CO -e 'print "Møøse\n"'
Møøse

Nel primo caso, Perl tratta la stringa come byte non elaborati e li stampa in quel modo. Poiché questi byte sono validi come UTF-8, hanno un aspetto corretto anche se Perl non sa realmente quali caratteri siano (ad esempio, la length("Møøse") restituirà 7, non 5). Una volta aggiunto -Mutf8 , Perl decodifica correttamente la sorgente UTF-8 in caratteri, ma l'output è in modalità Latin-1 per impostazione predefinita e la stampa da Latin-1 a un terminale UTF-8 non funziona. Solo quando si passa da STDOUT a UTF-8 usando -CO l'output sarà corretto.

use utf8 non influenza la codifica I / O standard né gli handle di file!

Gestione UTF-8 non valida

Lettura UTF-8 non valida

Durante la lettura dei dati codificati UTF-8, è importante essere consapevoli del fatto che i dati codificati UTF-8 possono essere non validi o non validi. Tali dati di solito non dovrebbero essere accettati dal tuo programma (a meno che tu non sappia cosa stai facendo). Quando si verificano inaspettatamente dati non validi, è possibile prendere in considerazione diverse azioni:

  • Stampa stacktrace o messaggio di errore e interrompi il programma con garbo, o
  • Inserire un carattere di sostituzione nel punto in cui è stata visualizzata la sequenza di byte non valida, stampare un messaggio di avviso su STDERR e continuare a leggere perché non è successo nulla.

Per impostazione predefinita, Perl ti warn della codifica dei glitch, ma non interromperà il tuo programma. È possibile interrompere il programma rendendo fatali gli avvertimenti UTF-8, ma sii consapevole dei caveat in Avvisi fatali .

L'esempio seguente scrive 3 byte nella codifica ISO 8859-1 su disco. Quindi tenta di leggere nuovamente i byte come dati codificati UTF-8. Uno dei byte, 0xE5 , è una sequenza di byte UTF-8 non valida:

use strict;
use warnings;
use warnings FATAL => 'utf8';

binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
my $bytes = "\x{61}\x{E5}\x{61}";  # 3 bytes in iso 8859-1: aåa
my $fn = 'test.txt';
open ( my $fh, '>:raw', $fn ) or die "Could not open file '$fn': $!";
print $fh $bytes;
close $fh;
open ( $fh, "<:encoding(utf-8)", $fn ) or die "Could not open file '$fn': $!";
my $str = do { local $/; <$fh> };
close $fh;
print "Read string: '$str'\n";

Il programma si interromperà con un avviso fatale:

utf8 "\xE5" does not map to Unicode at ./test.pl line 10.

La riga 10 è qui la penultima riga e l'errore si verifica nella parte della linea con <$fh> quando si tenta di leggere una riga dal file.

Se non si effettuano avvisi fatali nel programma precedente, Perl stamperà comunque l'avviso. Tuttavia, in questo caso proverà a recuperare dal byte 0xE5 inserendo i quattro caratteri \xE5 nello stream e quindi continuerà con il byte successivo. Di conseguenza, il programma stamperà:

Read string: 'a\xE5a'


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow