Perl Language
Unicode
サーチ…
備考
ファイル名エンコーディングに関する警告
ファイル名エンコーディングは、 プラットフォーム特有のものではなく、 ファイルシステム特有のものであることにも言及する価値があります 。
あるファイル名をエンコードして書き込むことができるという理由だけで、同じファイル名を読み込みしようとしたときにも同じことが起きると想定することは、決して完全に安全ではありません。
たとえば、UnicodeをサポートしていないFAT16
などのファイルシステムに書き込む場合、ファイル名は暗黙のうちにASCII互換の形式に変換されます。
しかし、それは他の呼び出しによって照会すると、同じことを呼ばれます例えば、読み、明示的な名前付けによってへの書き込み、ファイルが作成できることを前提としても、 あまり安全であるreaddir
あなたがして、指定よりも、あなたのファイル名に別のバイトを返すことがありますopen
。
VAXのようないくつかのシステムでは、OSによってファイル拡張子が変更される可能性があるので、 readdir
がfoo.bar
ようなファイル名に対してopen
で指定したのと同じファイル名を返すと常に考えることさえできません。
また、UNIXでは、 /
と\0
だけを除いて、OSが許すファイル名には、非常に自由な一連の合法的な文字があります.Windowsでは、ファイル名で禁止されている特定の文字の範囲があり、
ここでは十分な注意を払ってください。もしあなたが選択肢があるならば、ファイル名での巧妙なトリックを避けてください 。そして、常にあなたが使っている巧妙な技が一貫していることを確認するテストがあります。
CPAN
向けのコードを記述している場合など、コントロール外のプラットフォームで実行されるコードを書く場合は、 2倍の注意を払ってください。ユーザーベースの少なくとも5%は、選択、事故、またはコントロール外の権限によって、古代または壊れたテクノロジーが発生し、それらがバグを作成するために共謀することになります。
:エンコード(utf8)対utf8
UTF-8はPerlで文字列を表現するための内部形式の1つであるため、エンコード/デコードのステップをスキップすることがよくあります。 :encoding(utf-8)
代わりに、あなたのデータが既にUTF-8である場合は:utf8
使うだけでよいの:utf8
。 :utf8
は出力ストリームでは安全に使用できますが、入力ストリームでは無効なバイトシーケンスがあると内部の不整合が発生するため危険です。また、 :utf8
を入力に使用するとセキュリティ違反が発生する可能性があるため、 :encoding(utf-8)
が推奨されます。
UTF-8対utf8対UTF8
Perl v5.8.7
、 "UTF-8"
(ダッシュ付き)は、厳密でセキュリティに配慮した形式のUTF-8を意味します。一方、 "utf8"
は自由で自由な形式のUTF-8を意味します。
例えば、 "utf8"
は0xFFFFFFFF
ようにUnicodeに存在しないコードポイントに使用できます。これに対応して、 "\x{FE}\x{83}\x{BF}\x{BF}\x{BF}\x{BF}\x{BF}"
ような無効なUTF-8バイトシーケンスは、無効なユニコード(しかし、有効なPerlの)コードポイント( 0xFFFFFFFF
)使用して"utf8"
、一方で"UTF-8"
エンコーディングが有効なUnicodeの範囲外のコードポイントにデコードすることができないだろうし、あなたの置換文字(与えるだろう0xFFFD
代わりに)。
コード名は大文字小文字を区別しないので、 "UTF8"
同じである"utf8"
(すなわち、 非厳密変異体)。
詳細: UTF-8対UTF8対UTF8
もっと読む
PerlのUnicode処理の詳細は、次のソースで詳しく説明されています。
- perlunicode
- パーラーニット
- パーランニー
- Perlunifaq
- perlunicook
- utf8プラグマ
- unicode_strings機能
- オープンプラグマ
- PerlIO
- PerlIO :: encoding
- オープン関数
- エンコード
- perlrun - コマンドラインスイッチ
- 第6章Perlプログラミング
stackoverflow.comからの投稿(警告:最新のものではない可能性があります):
ユーチューブの動画:
- 2016年YAPCでリカルドが署名した数千万の奇妙なキャラクター 。
ファイル名を作成する
次の例では、UTF-8エンコーディングを使用してディスク上のファイル名(およびディレクトリ名)を表しています。別のエンコーディングを使用する場合は、 Encode::encode(...)
使用する必要があり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 $@;
ファイル名を読み込む
Perlは、組み込みの関数やモジュールから返されたファイル名のデコードを試みません。ファイル名を表すそのような文字列は、Perlがそれらを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/;
}
注意:ファイル名に無効なUTF-8がある場合は、上記の例でdecode_utf8( ... )
をdecode( 'utf-8', ... )
置き換えてください。これはdecode_utf8( ... )
同義語であり、 decode( 'utf8', ... )
とエンコーディングの間に差があるutf-8
およびutf8
(参照備考ここで詳細は以下)をutf-8
多いですutf8
よりも容認できるものを厳格にする。
1ライナーのコマンドラインスイッチ
utf8プラグマを有効にする
one-linerでutf8
プラグマを有効にするには、 -Mutf8
オプションを-Mutf8
perlインタプリタを-Mutf8
必要があります。
perl -Mutf8 -E 'my $人 = "human"; say $人'
-CスイッチによるUnicode処理
-C
コマンドラインフラグを使用すると、Unicode機能を制御できます。オプション文字のリストが続きます。
標準I / O
-
I
-STDIN
はUTF-8になりSTDIN
-
O
-STDOUT
はUTF-8になります -
E
-STDERR
はUTF-8になります -
S
-IOE
略語、標準I / OストリームはUTF-8になります
echo "Ματαιότης ματαιοτήτων" | perl -CS -Mutf8 -nE 'say "ok" if /Ματαιότης/'
スクリプトの引数
-
A
- UTF-8でエンコードされた文字列の配列として@ARGV
を扱います。
perl -CA -Mutf8 -E 'my $arg = shift; say "anteater" if $arg eq "муравьед"' муравьед
デフォルトのPerlIO層
-
i
- UTF-8は入力ストリーム用のデフォルトのPerlIOレイヤーです -
o
- UTF-8は出力ストリーム用のデフォルトのPerlIOレイヤーです -
D
-io
略語
perl -CD -Mutf8 -e 'open my $fh, ">", "utf8.txt" or die $!; print $fh "개미 조심해"'
-M
スイッチと-C
スイッチを組み合わせることができます。
perl -CASD -Mutf8 -E 'say "Ματαιότης ματαιοτήτων\n"';
標準I / O
標準I / Oファイルハンドル( STDIN
、 STDOUT
、およびSTDERR
)に使用されるエンコーディングは、 binmode
を使用してハンドルごとに個別に設定できます。
binmode STDIN, ':encoding(utf-8)';
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
注:一つは、一般的に好む読み出すとき:encoding(utf-8)
上:utf8
、参照備考詳細については。
また、 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'
あるいは、まだ開いていないファイルハンドルと標準のファイルハンドルの両方に、すべてのファイルハンドルを設定する:encoding(utf-8)
:
use open qw( :encoding(utf-8) :std );
ファイルハンドル
open()でエンコードを設定する
テキストファイルを開くときに、3つの引数open()
使って明示的にエンコーディングを指定することができます。ファイルハンドルに添付されたこのエンコーダー/デコーダーは、 "I / Oレイヤー"と呼ばれます。
my $filename = '/path/to/file';
open my $fh, '<:encoding(utf-8)', $filename or die "Failed to open $filename: $!";
:utf8
と:encoding(utf-8)
の違いについては、「 備考 」を参照してください。
binmode()でエンコーディングを設定する
あるいは、binmode()を使って個々のファイルハンドルのエンコーディングを設定することもできます:
my $filename = '/path/to/file';
open my $fh, '<', $filename or die "Failed to open $filename: $!";
binmode $fh, ':encoding(utf-8)';
オープンプラグマ
別々にファイルハンドルごとにエンコードを設定しないようにするには、 open
プラグマを使用して、以降のopen()
関数およびこのプラグマのレキシカルスコープ内の同様の演算子へのすべての呼び出しで使用されるデフォルトのI / Oレイヤーを設定できます。
# 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)';
コマンドラインでのエンコーディングの設定-Cフラグ
最後に、デフォルトのI / O層としてUTF-8を適用する-CD
フラグを付けてperlインタプリタを実行することもできます。ただし、このオプションは、予測も制御もできない特定のユーザーの動作に依存するため、避けるべきです。
utf8プラグマ:ソースでUnicodeを使用する
utf8
プラグマは、ソースコードがUTF-8として解釈されることを示します。もちろん、これはテキストエディタがUTF-8エンコードとしてソースを保存している場合にのみ機能します。
現在、文字列リテラルには任意のUnicode文字を含めることができます。識別子はUnicodeを含むこともできますが、単語のような文字だけです(詳細はperldataと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")
注意 :端末にテキストを印刷するときは、それがUTF-8をサポートしていることを確認してください。*
出力コードとソースコードの間に複雑で逆の直観的な関係が存在する可能性があります。 UTF-8端末で実行している場合、 utf8
プラグマを追加すると問題が発生する可能性があります。
$ 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
最初のケースでは、Perlは文字列を生のバイトとして扱い、それをそのまま出力します。これらのバイトは有効なUTF-8であるため、Perlは実際にどの文字が認識されていなくても正しく表示されます(例: length("Møøse")
は5ではなく7を返します)。 -Mutf8
を追加する-Mutf8
、PerlはUTF-8ソースを文字に正しくデコードしますが、出力はデフォルトでLatin-1モードであり、Latin-1をUTF-8端末に出力することはできません。 -CO
を使用してSTDOUT
をUTF-8に切り替えるときだけ、出力は正しいでしょう。
use utf8
しても、標準I / Oエンコーディングやファイルハンドルには影響しません!
無効なUTF-8の処理
無効なUTF-8を読む
UTF-8でエンコードされたデータを読むときは、UTF-8でエンコードされたデータが無効であるか、または形式が誤っている可能性があることに注意することが重要です。そのようなデータは通常、(あなたが何をしているのか分からない限り)あなたのプログラムによって受け入れられるべきではありません。予期せず不正なデータに遭遇した場合、さまざまなアクションが考えられます。
- スタックトレースまたはエラーメッセージを出力し、プログラムを正常に終了するか、または
- 不正なバイト列が現れた場所に置換文字を挿入し、STDERRに警告メッセージを出力し、何も起こらないまま読み込みを続けます。
デフォルトでは、Perlはグリッチのエンコードについてwarn
ますが、プログラムを中止することはありません。 UTF-8の警告を致命的にすることでプログラムを中断させることができますが、致命的な警告の警告に注意してください。
次の例では、ISO 8859-1エンコーディングの3バイトをディスクに書き込みます。その後、バイトをUTF-8でエンコードされたデータとして再度読み込みます。バイト0xE5
1つが無効なUTF-8 1バイトシーケンスです。
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";
プログラムは致命的な警告で中断します:
utf8 "\xE5" does not map to Unicode at ./test.pl line 10.
行10は2番目の最後の行になり、ファイルから行を読み込もうとすると<$fh>
行の部分にエラーが発生します。
上記のプログラムで警告を致命的にしないと、Perlは警告を出力します。ただし、この場合、ストリームに\xE5
という4文字を挿入して、不正なバイト0xE5
から回復しようとし、次のバイトを続行します。結果として、プログラムは次のように印刷します。
Read string: 'a\xE5a'