Recherche…


Remarques

Un avertissement sur le codage des noms de fichiers


Il convient de mentionner que le codage de nom de fichier n’est pas seulement spécifique à la plate-forme, mais aussi au système de fichiers .

Il n'est jamais tout à fait sûr de supposer (mais c'est souvent le cas) que le simple fait que vous puissiez encoder et écrire sur un nom de fichier donné, lorsque vous essayez d'ouvrir le même nom pour la lecture, sera toujours appelé.

Par exemple, si vous écrivez dans un système de fichiers tel que FAT16 qui ne prend pas en charge unicode, vos noms de fichiers peuvent être traduits en silence dans des formulaires compatibles ASCII.

Mais il est encore moins sûr de supposer qu'un fichier , vous pouvez créer, lire et écrire en nommant explicitement que l' on appellera la même chose lorsqu'il est interrogé par d' autres appels, par exemple, readdir peut renvoyer différents octets pour votre nom de fichier que vous avez spécifié pour open .

Sur certains systèmes tels que VAX, vous ne pouvez pas toujours supposer que readdir renverra le même nom de fichier que vous avez spécifié avec open pour les noms de fichiers aussi simples que foo.bar , car les extensions de noms de fichiers peuvent être gérées par le système d'exploitation.

De plus, sous UNIX, il existe un ensemble très libéral de caractères légaux pour les noms de fichiers que le système d'exploitation autorise, à l'exception de / et \0 , comme sur Windows, il existe des plages de caractères interdites dans les noms de fichiers.

Faites preuve de prudence beaucoup ici, d' éviter des trucs de fantaisie avec les noms de fichiers si vous avez le choix, et ont toujours des tests pour vous assurer que tous les trucs de fantaisie que vous faites usage sont compatibles.

Faites preuve d'autant de prudence si vous écrivez du code destiné à être exécuté sur des plates-formes hors de votre contrôle, par exemple si vous écrivez du code destiné à CPAN , et supposez qu'au moins 5% de votre base d'utilisateurs sera bloquée par certains. une technologie ancienne ou brisée, que ce soit par choix, par accident ou par des pouvoirs indépendants de leur volonté, et que ceux-ci concourront à créer des bogues pour eux.

: encodage (utf8) vs: utf8


Comme UTF-8 est l'un des formats internes de représentation des chaînes en Perl, l'étape de codage / décodage peut souvent être ignorée. Au lieu de :encoding(utf-8) , vous pouvez simplement utiliser :utf8 , si vos données sont déjà dans UTF-8. :utf8 peut être utilisé en toute sécurité avec les flux de sortie, alors que pour le flux d'entrée, il peut être dangereux, car il provoque une incohérence interne lorsque vous avez des séquences d'octets invalides. En outre, l'utilisation de :utf8 pour la saisie peut entraîner des failles de sécurité. L'utilisation de :encoding(utf-8) est donc recommandée.

Plus de détails: Quelle est la différence entre: encoding et: utf8

UTF-8 vs utf8 vs UTF8


A partir de Perl v5.8.7 , "UTF-8" (avec un tiret) signifie UTF-8 dans sa forme stricte et consciente de la sécurité, tandis que "utf8" signifie UTF-8 dans sa forme libérale et libre.

Par exemple, "utf8" peut être utilisé pour les points de code qui n'existent pas dans Unicode, comme 0xFFFFFFFF . De manière correspondante, les séquences d'octets UTF-8 invalides comme "\x{FE}\x{83}\x{BF}\x{BF}\x{BF}\x{BF}\x{BF}" se décoderont en un invalide codepoint Unicode (mais Perl valide) ( 0xFFFFFFFF ) lors de l' utilisation "utf8" , alors que le "UTF-8" le codage ne permettrait pas le décodage de codepoints en dehors de la plage d'Unicode valide et vous donnera un caractère de substitution ( 0xFFFD ) à la place.

Comme les noms de codage sont insensibles à la casse, "UTF8" est identique à "utf8" (variante non stricte ).

Plus de détails: UTF-8 contre utf8 contre UTF8

Plus de lecture


Les détails sur la gestion Unicode de Perl sont décrits plus en détail dans les sources suivantes:

Messages de stackoverflow.com (mise en garde: peut ne pas être à jour):

Vidéos youtube:

Créer des noms de fichiers

Les exemples suivants utilisent le codage UTF-8 pour représenter les noms de fichiers (et les noms de répertoires) sur le disque. Si vous voulez utiliser un autre encodage, vous devez utiliser 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 $@;

Lire les noms de fichiers

Perl ne tente pas de décoder les noms de fichiers renvoyés par des fonctions ou des modules intégrés. De telles chaînes représentant des noms de fichiers doivent toujours être décodées explicitement, afin que Perl les reconnaisse comme 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/;
}

Note: si vous êtes préoccupé par l'invalidité de l'UTF-8 dans les noms de fichiers, l'utilisation de decode_utf8( ... ) dans les exemples ci-dessus devrait probablement être remplacée par decode( 'utf-8', ... ) . En effet, decode_utf8( ... ) est synonyme de decode( 'utf8', ... ) et il existe une différence entre les encodages utf-8 et utf8 (voir Remarques ci-dessous pour plus d'informations) où utf-8 est plus strict sur ce qui est acceptable que utf8 .

Commutateurs de ligne de commande pour un interlocuteur

Activer le pragma utf8

Pour activer le pragma utf8 dans une ligne, l'interpréteur perl doit être appelé avec l'option -Mutf8 :

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

Manipulation Unicode avec le commutateur -C

L'indicateur de ligne de commande -C vous permet de contrôler les fonctionnalités Unicode. Il peut être suivi d'une liste de lettres d'options.

E / S standard

  • I - STDIN sera en UTF-8
  • O - STDOUT sera en UTF-8
  • E - STDERR sera en UTF-8
  • S - raccourci pour IOE , les flux d'E / S standard seront en UTF-8
echo "Ματαιότης ματαιοτήτων" | perl -CS -Mutf8 -nE 'say "ok" if /Ματαιότης/'

Les arguments du script

  • A - traite @ARGV comme un tableau de chaînes codées en UTF-8
perl -CA -Mutf8 -E 'my $arg = shift; say "anteater" if $arg eq "муравьед"' муравьед

Couche PerlIO par défaut

  • i - UTF-8 est la couche PerlIO par défaut pour les flux d'entrée
  • o - UTF-8 est la couche PerlIO par défaut pour les flux de sortie
  • D - sténographie pour io
perl -CD -Mutf8 -e 'open my $fh, ">", "utf8.txt" or die $!; print $fh "개미 조심해"'

-M commutateurs -M et -C peuvent être combinés:

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

E / S standard

Le codage à utiliser pour les STDIN E / S standard ( STDIN , STDOUT et STDERR ) peut être défini séparément pour chaque binmode aide de binmode :

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

Note: en lecture on préférerait en général :encoding(utf-8) sur :utf8 , voir Remarques pour plus d'informations.

Alternativement, vous pouvez utiliser le 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'

Alternativement, pour définir tous les descripteurs de fichiers (à la fois ceux qui doivent encore être ouverts et ceux à ouvrir) :encoding(utf-8) :

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

Poignées de fichier

Réglage de l'encodage avec open ()

Lors de l'ouverture d'un fichier texte, vous pouvez spécifier son encodage explicitement avec un open() trois arguments. Ce en / décodeur attaché à un descripteur de fichier est appelé "couche d'E / S":

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

Voir Remarques pour une discussion des différences entre :utf8 et :encoding(utf-8) .

Définition du codage avec binmode ()

Vous pouvez également utiliser binmode () pour définir l'encodage pour chaque descripteur de fichier:

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

pragma ouvert

Pour éviter de définir séparément le codage pour chaque descripteur de fichier, vous pouvez utiliser le pragma open pour définir une couche d'E / S par défaut utilisée par tous les appels suivants à la fonction open() et aux opérateurs similaires dans la portée lexicale de ce 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)';

Définition du codage avec la ligne de commande -C flag

Enfin, il est également possible d'exécuter l'interpréteur perl avec un indicateur -CD qui applique UTF-8 comme couche d'E / S par défaut. Cependant, cette option doit être évitée car elle repose sur un comportement spécifique de l’utilisateur qui ne peut être ni prédit ni contrôlé.

Le pragma utf8: utiliser Unicode dans vos sources

Le pragma utf8 indique que le code source sera interprété comme UTF-8. Bien sûr, cela ne fonctionnera que si votre éditeur de texte enregistre également la source au format UTF-8.

Maintenant, les littéraux de chaîne peuvent contenir des caractères Unicode arbitraires. les identificateurs peuvent également contenir Unicode, mais uniquement des caractères de type mot (voir perldata et perlrecharclass pour plus d'informations):

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")

Remarque : Lorsque vous imprimez du texte sur le terminal, assurez-vous qu'il prend en charge UTF-8. *

Il peut exister des relations complexes et contre-intuitives entre la sortie et le codage source. En cours d'exécution sur un terminal UTF-8, vous pouvez constater que l'ajout du pragma utf8 semble casser des choses:

$ 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

Dans le premier cas, Perl traite la chaîne comme des octets bruts et les imprime comme cela. Comme ces octets sont valides UTF-8, ils semblent corrects même si Perl ne sait pas vraiment quels caractères ils sont (par exemple, la length("Møøse") renverra 7, pas 5). Une fois que vous ajoutez -Mutf8 , Perl décode correctement la source UTF-8 en caractères, mais la sortie est en mode Latin-1 par défaut et l'impression Latin-1 sur un terminal UTF-8 ne fonctionne pas. Ce n'est que lorsque vous passez de STDOUT à UTF-8 en utilisant -CO que la sortie sera correcte.

use utf8 n'affecte pas l'encodage d'E / S standard ni les descripteurs de fichiers!

Gestion des UTF-8 invalides

Lecture invalide UTF-8

Lors de la lecture de données encodées en UTF-8, il est important de savoir que les données encodées en UTF-8 peuvent être invalides ou mal formées. Ces données ne devraient généralement pas être acceptées par votre programme (sauf si vous savez ce que vous faites). En cas de rencontre inopinée de données mal formées, différentes actions peuvent être envisagées:

  • Imprimer le stacktrace ou le message d'erreur, et abandonner le programme normalement, ou
  • Insérez un caractère de substitution à l'endroit où la séquence d'octets mal formée est apparue, imprimez un message d'avertissement à STDERR et continuez à lire car rien ne s'est produit.

Par défaut, Perl vous warn de l'encodage des erreurs, mais il n'abandonnera pas votre programme. Vous pouvez faire votre programme abort en faisant des avertissements UTF-8 fatale, mais être au courant des mises en garde Avertissements Fatal .

L'exemple suivant écrit 3 octets dans le codage ISO 8859-1 sur le disque. Il essaie ensuite de relire les octets en tant que données encodées en UTF-8. L'un des octets, 0xE5 , est une séquence d'octets UTF-8 invalide:

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";

Le programme sera interrompu par un avertissement fatal:

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

La ligne 10 est la deuxième dernière ligne, et l'erreur se produit dans la partie de la ligne avec <$fh> lorsque vous essayez de lire une ligne du fichier.

Si vous ne faites pas d'avertissement fatal dans le programme ci-dessus, Perl imprimera toujours l'avertissement. Cependant, dans ce cas, il essaiera de récupérer l'octet mal formé 0xE5 en insérant les quatre caractères \xE5 dans le flux, puis poursuivra l'octet suivant. En conséquence, le programme imprimera:

Read string: 'a\xE5a'


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow