Perl length関数と全角文字
はじめに
Perlにlength関数があります。これは、文字列の総バイト数を返す関数です。よって、日本語などの全角文字が入っていた場合2バイトとして返されるため、「文字数」を調べることが出来ません。
そこで、ここでは全角文字が混じっていてもきちんと文字数を返せるような関数を作ろうと思います。
ちなみに、文字コードはシフトJISコードを前提としています。ほかの文字コードでは正常に動作しません。
length関数
とりあえずlength関数を使ってみます。
length("perl") → 4 length("全角文字") → 8 length("シフトJIS") → 9
このように、ただバイト数を返すだけです。文字数ではありません。
シフトJISコードでの全角文字
というわけで、全角文字と半角文字を判別し、別々に数えればいいことになります。その判別には、シフトJISコードでの全角文字の表現の特徴を利用します。
シフトJISコードでは、全角文字を表示できますが、その際2バイトで表現します(「猫」という文字であれば、「94 4c」(16進数)となります)。というわけで、全角文字を2バイト文字と呼びます。半角文字では1バイトです
2バイト文字では、第1バイト、第2バイトでそれぞれ使用する値の範囲が決まっています。そこを調べれば、全角文字か半角文字か判別することが出来ます。
判別には、正規表現を使います。文で説明してばかりでもわかりにくいので、そろそろ実際のコードを載せます。
コードと説明
とりあえずコードは以下のようになります。これについて少しずつ説明していこうと思います。
sub zlength { $_ = $_[0]; # 全角文字数を数え、全角文字を消去する $lz = s/[\x81-\x9f\xe0-\xfc][\x40-\x7e\x80-\xfc]//g; # 半角文字数を数える $lh = length($_); # 全角・半角の文字数を足して返す return $lz + $lh; }
$_ = $_[0];
まずはこれで、引数を$_という変数に格納しています。「$_」と「$_[0]」はまったく別のものなので注意。なぜ「$_」という変数に格納するのかというと、s//で置き換えするのが「$_」に格納されている値だからです。
$lz = s/[\x81-\x9f\xe0-\xfc][\x40-\x7e\x80-\xfc]//g;
まず、s//関数で、変数「$_」に格納されている文字列の、全角文字を消去しています。そしてその変換した数を変数「$lz」に格納しています。これで、$_の中身は半角文字だけに、$lzの中身は全角文字の文字数になります。
$lh = length($_);
上の作業により、$_の中身は半角文字だけになっています。つまり全て1バイトの文字です。というわけで、length関数を使うと、半角文字の文字数を得ることが出来ます。それを変数「$lh」に格納しています。
return $lz + $lh;
最後に、求めた全角文字数と半角文字数を足して、返しています。これで、無事にきちんとした「文字数」を求めることが出来ました。