Suche…


Bemerkungen

Eine Warnung zur Dateinamenkodierung


Erwähnenswert ist, dass Filename Encoding nicht nur plattformspezifisch ist, sondern auch dateisystemspezifisch .

Es ist nie völlig sicher, anzunehmen (ist es aber meistens), nur weil Sie einen bestimmten Dateinamen kodieren und schreiben können, wenn Sie später versuchen, denselben Dateinamen zum Lesen zu öffnen, wird er immer noch als dasselbe bezeichnet.

Wenn Sie beispielsweise in ein Dateisystem wie FAT16 schreiben, das Unicode nicht unterstützt, werden Ihre Dateinamen möglicherweise automatisch in ASCII-kompatible Formulare übersetzt.

Es ist jedoch noch weniger sicher anzunehmen, dass eine Datei, die Sie durch explizite Benennung erstellen, lesen und schreiben können, bei einer readdir durch andere Aufrufe dasselbe heißt. Zum Beispiel gibt readdir möglicherweise andere Bytes für Ihren Dateinamen zurück, als Sie zum open .

Auf manchen Systemen wie VAX, können Sie nicht einmal immer davon ausgehen , dass readdir die gleichen Dateinamen Sie mit angegebener Rückkehr open für Dateinamen so einfach wie foo.bar , weil Dateierweiterungen von den OS verstümmelt werden können.

Unter UNIX gibt es einen sehr liberalen Satz gesetzlicher Zeichen für Dateinamen, die das Betriebssystem zulässt, mit Ausnahme von / und \0 , wobei wie unter Windows bestimmte Zeichenbereiche vorhanden sind, die in Dateinamen verboten sind und Fehler verursachen.

Übung viel Vorsicht hier, vermeiden ausgefallenen Tricks mit Dateinamen , wenn Sie die Wahl haben, und immer Tests müssen sicherstellen , dass alle ausgefallenen Tricks Sie Gebrauch machen konsistent sind.

Seien Sie doppelt so vorsichtig, wenn Sie Code schreiben, der auf Plattformen außerhalb Ihrer Kontrolle ausgeführt werden soll, z. B. wenn Sie Code schreiben, der für CPAN , und davon ausgehen, dass mindestens 5% Ihrer Benutzerbasis nicht mehr verwendet werden alte oder kaputte Technologie, entweder durch Wahl, durch Zufall oder durch Kräfte, die außerhalb ihrer Kontrolle liegen, und dass diese verschwören werden, um Fehler für sie zu schaffen.

: Kodierung (utf8) vs: utf8


Da UTF-8 eines der internen Formate für die Darstellung von Zeichenfolgen in Perl ist, kann der Kodierungs- / Dekodierschritt oft übersprungen werden. Anstelle von :encoding(utf-8) können Sie einfach :utf8 , wenn Ihre Daten bereits in UTF-8 enthalten sind. :utf8 kann sicher mit Ausgabeströmen verwendet werden, während es für Eingabeströme gefährlich sein kann, da es bei ungültigen Byte-Sequenzen zu internen Inkonsistenzen führt. Die Verwendung von :utf8 für die Eingabe kann zu Sicherheitsverletzungen führen. Daher ist die Verwendung von :encoding(utf-8) ratsam.

Weitere Details: Was ist der Unterschied zwischen: Encoding und: utf8

UTF-8 gegen UTF8 gegen UTF8


Ab Perl v5.8.7 "UTF-8" (mit Bindestrich) UTF-8 in seiner strengen und sicherheitsbewussten Form, wohingegen "utf8" UTF-8 "utf8" UTF-8 in seiner liberalen und lockeren Form bedeutet.

Beispielsweise kann "utf8" für Codepunkte verwendet werden, die in Unicode nicht vorhanden sind, 0xFFFFFFFF . B. 0xFFFFFFFF . Dementsprechend werden ungültige UTF-8-Byte-Sequenzen wie "\x{FE}\x{83}\x{BF}\x{BF}\x{BF}\x{BF}\x{BF}" in eine Ungültiger Unicode-Codepunkt (aber gültiger Perl- 0xFFFFFFFF ) ( 0xFFFFFFFF ) bei Verwendung von "utf8" , während die Codierung "UTF-8" Codierung außerhalb des gültigen Unicode-Bereichs nicht zulässt und stattdessen ein Substitutionszeichen ( 0xFFFD ) enthält.

Da bei Namen der Kodierung die Groß- und Kleinschreibung nicht "UTF8" wird, ist "UTF8" dasselbe wie "utf8" (dh nicht strikte Variante).

Weitere Details: UTF-8 vs. utf8 vs. UTF8

Mehr lesen


Details zur Unicode-Verarbeitung von Perl werden in den folgenden Quellen ausführlicher beschrieben:

Beiträge von stackoverflow.com (Vorbehalt: ist möglicherweise nicht auf dem neuesten Stand):

Youtube Videos:

Erstellen Sie Dateinamen

In den folgenden Beispielen wird die UTF-8-Codierung verwendet, um Dateinamen (und Verzeichnisnamen) auf der Festplatte darzustellen. Wenn Sie eine andere Codierung verwenden möchten, sollten Sie 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 $@;

Dateinamen lesen

Perl versucht nicht, Dateinamen zu dekodieren, die von integrierten Funktionen oder Modulen zurückgegeben werden. Solche Zeichenfolgen, die Dateinamen darstellen, sollten immer explizit dekodiert werden, damit Perl sie als Unicode erkennt.

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/;
}

Hinweis: Wenn Sie besorgt sind, dass UTF-8 in den Dateinamen ungültig ist, sollte die Verwendung von decode_utf8( ... ) in den obigen Beispielen wahrscheinlich durch decode( 'utf-8', ... ) . Dies liegt daran , decode_utf8( ... ) ist ein Synonym für decode( 'utf8', ... ) - utf-8 utf8 utf-8 decode( 'utf8', ... ) und es gibt einen Unterschied zwischen den Kodierungen utf-8 - utf-8 und utf8 - utf8 (siehe Anmerkungen unten für weitere Informationen) , in utf-8 - utf-8 ist mehr streng auf was ist akzeptabel als utf8 .

Befehlszeilenschalter für Einzeiler

Aktivieren Sie das utf8-Pragma

Um das utf8 Pragma in einem -Mutf8 zu aktivieren, sollte der Perl-Interpreter mit der Option -Mutf8 :

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

Unicode-Handling mit -C-Schalter

Mit dem -C Befehlszeilenflag können Sie die Unicode-Funktionen steuern. Es kann eine Liste von Optionsbuchstaben folgen.

Standard-E / A

  • I - STDIN wird in UTF-8 sein
  • O - STDOUT wird in UTF-8 sein
  • E STDERR wird in UTF-8 enthalten
  • S - Abkürzung für IOE , Standard-E / A-Streams werden in UTF-8 angezeigt
echo "Ματαιότης ματαιοτήτων" | perl -CS -Mutf8 -nE 'say "ok" if /Ματαιότης/'

Argumente des Skripts

  • A - behandelt @ARGV als ein Array von UTF-8- codierten Zeichenfolgen
perl -CA -Mutf8 -E 'my $arg = shift; say "anteater" if $arg eq "муравьед"' муравьед

Standard-PerlIO-Ebene

  • i - UTF-8 ist die Standard-PerlIO-Schicht für Eingabeströme
  • o - UTF-8 ist der Standard-PerlIO-Layer für Ausgabestreams
  • D - Abkürzung für io
perl -CD -Mutf8 -e 'open my $fh, ">", "utf8.txt" or die $!; print $fh "개미 조심해"'

-M und -C Schalter können kombiniert werden:

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

Standard-E / A

Die für die Standard-E / A-Dateihandles ( STDIN , STDOUT und STDERR ) zu verwendende Kodierung kann für jeden binmode mithilfe von binmode separat binmode :

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

Hinweis: Beim Lesen würde man generell :encoding(utf-8) vorziehen :encoding(utf-8) gegenüber :utf8 ; weitere Informationen finden Sie unter Bemerkungen .

Alternativ können Sie das open Pragma verwenden.

# 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'

Alternativ können Sie alle Dateihandles festlegen (sowohl die noch zu öffnenden als auch die Standard-Dateien), die verwendet werden sollen :encoding(utf-8) :

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

Dateihandles

Codierung mit open () setzen

Beim Öffnen einer Textdatei können Sie die Kodierung explizit mit einem Argument mit drei Argumenten open() angeben. Dieser an einen Dateihandle angebrachte En- / Decoder wird als "E / A-Schicht" bezeichnet:

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

In den Anmerkungen finden Sie eine Erläuterung der Unterschiede zwischen :utf8 und :encoding(utf-8) .

Codierung mit binmode () einstellen

Alternativ können Sie binmode () verwenden, um die Kodierung für einzelne Dateihandles festzulegen:

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

offenes Pragma

Um zu vermeiden, dass die Codierung für jedes Dateihandle separat festgelegt wird, können Sie mit dem open Pragma eine Standard-E / A-Ebene festlegen, die von allen nachfolgenden Aufrufen der open() Funktion und ähnlichen Operatoren im lexikalischen Bereich dieses Pragmas verwendet wird:

# 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)';

Codierung mit Kommandozeile setzen -C Flag

Schließlich ist es auch möglich, den Perl-Interpreter mit einem -CD Flag auszuführen, das UTF-8 als Standard-E / A-Layer verwendet. Diese Option sollte jedoch vermieden werden, da sie auf ein bestimmtes Benutzerverhalten angewiesen ist, das weder vorhergesagt noch kontrolliert werden kann.

Das utf8-Pragma: Verwenden Sie Unicode in Ihren Quellen

Das utf8 Pragma zeigt an, dass der Quellcode als UTF-8 interpretiert wird. Das funktioniert natürlich nur, wenn Ihr Texteditor die Quelle auch als UTF-8-codiert speichert.

String-Literale können jetzt beliebige Unicode-Zeichen enthalten. Bezeichner können auch Unicode, aber nur wortartige Zeichen enthalten (weitere Informationen finden Sie unter Perldata und Perlrecharclass ):

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

Hinweis : Wenn Sie Text auf das Terminal drucken, stellen Sie sicher, dass UTF-8 unterstützt wird. *

Zwischen Ausgabe und Quellcodierung kann es komplexe und kontraintuitive Beziehungen geben. Wenn Sie auf einem UTF-8-Terminal laufen, werden Sie möglicherweise feststellen, dass das Hinzufügen des utf8 Pragmas einige Dinge zu zerstören scheint:

$ 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

Im ersten Fall behandelt Perl die Zeichenfolge als unformatierte Bytes und gibt sie so aus. Da diese Bytes zufällig gültiges UTF-8 sind, sehen sie korrekt aus, obwohl Perl nicht wirklich weiß, um welche Zeichen es sich handelt (z. B. length("Møøse") gibt 7 und nicht 5 zurück). Nachdem Sie -Mutf8 , dekodiert Perl die UTF-8-Quelle korrekt in Zeichen. Die Ausgabe erfolgt jedoch standardmäßig im Latin-1-Modus. Das Drucken von Latin-1 auf einem UTF-8-Terminal funktioniert nicht. Nur wenn Sie STDOUT mit -CO auf UTF-8 umschalten, ist die Ausgabe korrekt.

use utf8 wirkt sich nicht auf die Standard-E / A-Kodierung oder Dateizugriffsnummern aus!

Umgang mit ungültigem UTF-8

Lesen ungültiger UTF-8

Beim Lesen von UTF-8-kodierten Daten ist es wichtig zu wissen, dass die UTF-8-kodierten Daten ungültig oder fehlerhaft sein können. Solche Daten sollten normalerweise nicht von Ihrem Programm akzeptiert werden (es sei denn, Sie wissen, was Sie tun). Bei unerwarteten fehlerhaften Daten können verschiedene Aktionen in Betracht gezogen werden:

  • Drucken Sie die Stacktrace- oder Fehlermeldung und brechen Sie das Programm ordnungsgemäß ab, oder
  • Fügen Sie an der Stelle, an der die fehlerhafte Bytefolge erschienen ist, ein Ersatzzeichen ein, drucken Sie eine Warnmeldung an STDERR und lesen Sie weiter, da nichts passiert ist.

Perl warn Sie standardmäßig über das Kodieren von Störungen, aber Ihr Programm wird dadurch nicht abgebrochen. Sie können Ihr Programm zum Abbruch bringen, indem Sie UTF-8-Warnungen tödlich machen. Beachten Sie jedoch die Einschränkungen in Tödlichen Warnungen .

Das folgende Beispiel schreibt 3 Byte bei der Kodierung von ISO 8859-1 auf die Festplatte. Es versucht dann, die Bytes als UTF-8-codierte Daten erneut zu lesen. Eines der Bytes, 0xE5 , ist eine ungültige 1-Byte-Sequenz von UTF-8:

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

Das Programm bricht mit einer fatalen Warnung ab:

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

Zeile 10 ist hier die vorletzte Zeile, und der Fehler tritt im Teil der Zeile mit <$fh> wenn versucht wird, eine Zeile aus der Datei zu lesen.

Wenn Sie im obigen Programm keine schwerwiegenden Warnungen ausgeben, druckt Perl die Warnung trotzdem. In diesem Fall wird jedoch versucht, das fehlerhafte Byte 0xE5 indem die vier Zeichen \xE5 in den Stream \xE5 werden. Anschließend wird mit dem nächsten Byte \xE5 . Als Ergebnis druckt das Programm:

Read string: 'a\xE5a'


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow