camel

ぎゃあぁぁ

length関数で文字列の長さを求める - perl初心者BLOG - Hatena::Group::Perl
日本語の文字数を正確に求めたい場合、use encodingを指定する

use encoding;は、jperlなど、かつて存在したL10Nされたperl用に書かれたレガシースクリプトを、モダンperlで動かすときのためのおまじないです。こういう目的で利用すべきではありません。

このあたりのことは、以前

でも書いたのですが、大事なことなのでまた書きます。

スクリプトはUTF-8で書き、use utf8;する

のがモダンPerlのあり方です。

#!/usr/bin/perl
use strict;
use warnings;
{
  my $string = "dankogai小飼弾";
  printf "length('%s') == %d\n", $string, length($string);
}
{
  use utf8;
  my $string = "dankogai小飼弾";
  printf "length('%s') == %d\n", $string, length($string);
}

見ての通り、utf8プラグマは lexical scope で効きます。encodingプラグマではこうは行きません。

Wide character in printという warning が出ていますが、これは「UTF-8として扱われている文字列を、バイトストリームとして扱っています」という警告です。これを消すためには、STDOUTがUTF-8ストリームであることを教える必要があります。

あと、utf8プラグマが効いている状態で、文字列が何文字かではなく文字列が何バイトかを知るためには、bytes::length()を使います。

以上をふまえたサンプルが以下です。

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use bytes (); # () をお忘れなく

my $string = "dankogai小飼弾";
binmode STDOUT, ':utf8'; # STDOUTはUTF-8ストリーム
printf "length('%s') == %d\n", $string, length($string);
printf "bytes::length('%s') == %d\n", $string, bytes::length($string);

UTF-8以外の文字コードは、外部化するかバイト列として表現した上でEncodeで処理する

基本的なやり方は以前書いたとおりです。

どうしても外部化したくない場合には、明示的にバイト列として表現しましょう。以下はその例です。

#!/usr/bin/perl
use strict;
use warnings;
use Encode;

my $bytes = "\x95\x5C"; # 「表」をShift_JISで
my $string = decode "sjis", $bytes;
printf "length(\$string) == %d\n", length($string);
printf "length(\$bytes) == %d\n", length($bytes);

なぜそうすべきかというと、Shift_JISやBIG-5などでは、2バイト文字中にASCIIの記号が混じってしまうことがあるからです。以下のコードをShift_JISで保存して確認してみてください。

#!/usr/bin/perl
use strict;
use warnings;
use Encode;

my $bytes = "表";
my $string = decode "sjis", $bytes;
printf "length(\$string) == %d\n", length($string);
printf "length(\$bytes) == %d\n", length($bytes);

これは、表のSJIS表記、\x95\x5Cの二バイト目がバックスラッシュなので、"表""\x95\""と解釈されてしまうためです。EUCではこういう問題は発生しないのですが、こうした問題のわかりにくさと手間を考えたら、新たなスクリプトははじめからUTF-8で書くのが圧倒的に一番楽な方法ということになります。

use encoding;で新たなスクリプトを書かない

というわけで大事なことなので二度言うと、use encoding;はどうしても旧いスクリプトを動かしたいときだけに使い、新たなスクリプトはUTF-8で書くようにしましょう。幸せになれるかはさておき、不幸にあう確率はずっと下がります。

Dan the Maintainer Thereof