PerlにおけるUTF-8フラグと、その周辺の話し

PerlScriptをUTF-8で記述し、use utf8;を付けた場合、Script内で取り扱う文字列の「UTF-8フラグ」がオンになります。
私は個人的に、ここの理解に時間がかかったので知識を共有します。

UTF-8フラグとは何か

簡単に言うと「UTF-8文字の解釈方法を切り替えるスイッチ」です。
UTF-8フラグがオンの場合、「あ」は『1文字』です。
UTF-8フラグがオフの場合、「あ」はオクテットとして解釈されるため『3文字』、つまり3バイト(32bitの場合)として解釈されます。

UTF-8フラグをオンにする方法

use utf8プラグマを使う方法と、任意にオンにする方法があります。

use utf8プラグマを使ってオンにする

Scriptで文字列のUTF-8フラグをオンにしたい位置に

use utf8;

を記述します。

任意にオンにする

UTF-8フラグをオンにしたい文字列が格納された変数を、以下のように処理します。


下記の例では、$stringに格納された文字列に対してUTF-8フラグをオンにし、$resultへ代入しています。

$result = Encode::decode_utf8($string);

use utf8プラグマの有効範囲

レキシカルスコープ内となります。
ものすごく乱暴に書くと、
「{ }の外」に書くと、『スクリプトファイル全体』に有効となり、
「{ }の中」に書くと、『{ }が閉じられるまで』有効となります。


以下の例では、「# 有効範囲 開始」〜「# 有効範囲 終了」までの範囲でuse utf8プラグマが有効です。
サブルーチンを有効範囲内から呼び出しても、use utf8プラグマは有効になりません。

{  # 有効範囲 開始
	use utf8;
	{
		my $string = "あ";
		print length($string)."\n";  # 1と出力されます。
	}
	my $string = "あ";
	print length($string)."\n";      # 1と出力されます。

	&test();
	&pkg::pkg_test();

}  # 有効範囲 終了

sub test{
	my $string = "あ";
	print length($string)."\n";      # 3と出力されます。
}

package pkg;
	sub pkg_test{
		my $string = "あ";
		print length($string)."\n";  # 3と出力されます。
	}

アラートに対するトラブルシューティング

use utf8プラグマでUTF-8フラグをオンにすると、コマンドラインでの実行時にエラーが生じる場合があります。

Wide character in print at [Script name] line [num].

UTF-8フラグがオンの状態で文字列を出力すると生じます。
UTF-8フラグをオフにする必要があります。

STDOUTの出力をUTF-8バイナリにする(UTF-8フラグはオフになる)
binmode(STDOUT,":utf8");
出力対象の変数のUTF-8フラグをオフにする
$result = Encode::encode_utf8($string);

Cannot decode string with wide characters at D:/usr/local/perl/lib/Encode.pm line 190.

Encode::from_toで、UTF-8フラグがオンの変数を変換しようとすると生じます。

変換対象の変数のUTF-8フラグをオフにする
$result = Encode::encode_utf8($string);