bytesプラグマを使うことで解決する。
(11/02/12)追記しました
何もせずに length をしてみると。
use strict; use warnings; use utf8; my $str = "あいうえお"; print length $str,"\n";
結果は文字数。
5
以下の用に bytesプラグマを使うことで、バイト数を取得できる。
use strict; use warnings; use utf8; my $str = "あいうえお"; { use bytes; print length $str,"\n"; }
結果は、バイト数
15
ブレースで囲むのは、bytesの効果が及ぶ範囲をレキシカルスコープに限定するため。
bytesは何をやってくれるのかというと…
use bytes プラグマはそれの現れたレキシカルスコープの残りで文字セマンティクスを無効化します。
http://fleur.hio.jp/perldoc/mix/pragma/bytes.html
(略)
Perl は文字データの表現を文字単位であると通常考えます. (例えばソースからくるデータは特定の文字エンコーディングで記されているでしょう.) use bytes が実行された時, そのエンコーディングは一時的に無視されます. そしてそれぞれの文字列はバイト列として処理されます
とのこと。
毎回ブレースで囲むのはちょっと…という場合は以下のように。
use bytes (); として、length の代わりに bytes::length を使用する。
use strict; use warnings; use utf8; use bytes (); my $str = "あいうえお"; print bytes::length( $str ), "\n";
結果
15
会社で調べたときに参考にさせてもらったブログと殆ど内容が被ってしまった。
追記
はてブで、id:hisaichi5518 さんより、bytes.pm が廃止予定というご指摘をいただきました。
全く知りませんでした。ありがとうございます。
bytes.pm を使わない場合は、utf8::is_utf8 と、Encode::encode を使うことで同じことができます。
use strict; use warnings; use utf8; use Encode; use bytes(); my $str = "あいうえお"; if ( utf8::is_utf8( $str ) ) { print length( Encode::encode( 'utf8', $str ) ), "\n"; } else { print length($str), "\n"; }
結果
15
というわけで、将来の移植性を考えると bytesプラグマを使うことは避けておいたほうが良さそうです。
(さらに追記)
今回のやりたいこと(utf8プラグマ使用時の文字列のバイト数の取得)を実現するのに、utf8::is_utf8 を使う必要性は全くなかった。
したがって、ほんとうはコードは以下のようにあるべき。
use strict; use warnings; use utf8; use Encode; use bytes(); my $str = "あいうえお"; print length( Encode::encode( 'utf8', $str ) ), "\n";