{ブロック}の外でのみ use utf8; したいのだが・・・
連投申し訳ありません。
「まるごとPerl」(2006年9月、インプレス刊)という本の「まるごとEncode」という記事に従ってEncodeの勉強をしています。
原記事は UNIX(というか端末コードをUTF-8に出来る環境)ですが、それをWindowsに移植しようとして苦労しています。
#! perl
# list3 -- UTF-8モードとバイトモードの切り替え
# インデントを表現するために全角空白を使っています
use strict;
use warnings;
binmode STDOUT, ':encoding(cp932)'; # 追加
# ブロックの外側ではUTF-8文字単位で解釈される
use utf8;
{
# ブロックの外側ではバイトモードが強制される
use bytes;
my $text = '漢字、カタカナ、ひらがなの混じったtext';
print Encode::decode('UTF-8', substr($text, 9, 12)); # カタカナと表示されたい
}
my $text = '漢字、カタカナ、ひらがなの混じったtext';
print substr($text, 3, 4); # カタカナと表示されたい
__END__
というプログラムを実行すると
C:\>list3.pl
カタカナカタカナ
と表示されてほしいのですが、
C:\>list3.pl
Cannot decode string with wide characters at C:/strawberry/perl/lib/Encode.pm li
ne 174.
と表示されます。
use utf8 を後ろにズラして
#! perl
# list3 -- UTF-8モードとバイトモードの切り替え
# インデントを表現するために全角空白を使っています
use strict;
use warnings;
binmode STDOUT, ':encoding(cp932)'; # 追加
{
# ブロックの外側ではバイトモードが強制される
use bytes;
my $text = '漢字、カタカナ、ひらがなの混じったtext';
print Encode::decode('UTF-8', substr($text, 9, 12)); # カタカナと表示されたい
}
# ブロックの外側ではUTF-8文字単位で解釈される
use utf8; # 移動
my $text = '漢字、カタカナ、ひらがなの混じったtext';
print substr($text, 3, 4); # カタカナと表示されたい
__END__
とするとうまく動いて
C:\>list3.pl
カタカナカタカナ
と表示されます。
#! perl
# list3 -- UTF-8モードとバイトモードの切り替え
# インデントを表現するために全角空白を使っています
use strict;
use warnings;
binmode STDOUT, ':encoding(cp932)'; # 追加
# ブロックの外側ではUTF-8文字単位で解釈される
use utf8;
my $text = '漢字、カタカナ、ひらがなの混じったtext'; # 移動
print substr($text, 3, 4); # カタカナと表示されたい # 移動
{
# ブロックの外側ではバイトモードが強制される
use bytes;
my $text = '漢字、カタカナ、ひらがなの混じったtext';
print Encode::decode('UTF-8', substr($text, 9, 12)); # カタカナと表示されたい
}
__END__
のようにするとやはり最初と同じエラーになりますが、
#! perl
# list3 -- UTF-8モードとバイトモードの切り替え
# インデントを表現するために全角空白を使っています
use strict;
use warnings;
binmode STDOUT, ':encoding(cp932)'; # 追加
# ブロックの外側ではUTF-8文字単位で解釈される
use utf8;
my $text = '漢字、カタカナ、ひらがなの混じったtext'; # 移動
print substr($text, 3, 4); # カタカナと表示されたい # 移動
no utf8; # 追加
{
# ブロックの外側ではバイトモードが強制される
use bytes;
my $text = '漢字、カタカナ、ひらがなの混じったtext';
print Encode::decode('UTF-8', substr($text, 9, 12)); # カタカナと表示されたい
}
__END__
だと大丈夫です。
結果として、ブロックの外で use utf8;、中では use bytes; という記事の著者の意図通りに動作しないようで、ブロックの中まで use utf8; が効いているようです・・・。
これは Perl の実装が変わったのでしょうか。
使用しているのは Windows XP Home SP3+Strawberry Perl v5.10.0 です。
お礼
ありがとうございます! 自作プロパティの場合IsまたはInが必要なんですね。 これ、5.12のときはIs、Inがなくてもできたようです。 ★ C:\Perl\perl>type utf8_unireg2.pl #! /bin/perl # # utf8_unireg.pl use 5.010; use strict; use warnings; use utf8; binmode STDOUT, ":encoding(shift_jis)"; my $str = "a:b:c:"; say join "|", ($str =~ /\p{AsciiAlpha}/g); sub AsciiAlpha { return <<END; 0041 005A # A-Z 0061 007A # a-z END } C:\Perl\perl>perl utf8_unireg2.pl a|b|c C:\Perl\perl>perl -v This is perl 5, version 12, subversion 1 (v5.12.1) built for MSWin32-x86-multi-thread Copyright 1987-2010, Larry Wall Perl may be copied only under the terms of either the Artistic License or the GNU General Public License, which may be found in the Perl 5 source kit. Complete documentation for Perl, including FAQ lists, should be found on this system using "man perl" or "perldoc perl". If you have access to the Internet, point your browser at http://www.perl.org/, the Perl Home Page. C:\Perl\perl> ★ ところが、5.16になってからは、(Is|In)が必要になったようです。 ★ C:\Perl\perl>perl -v This is perl 5, version 16, subversion 3 (v5.16.3) built for MSWin32-x86-multi-thread (with 1 registered patch, see perl -V for more detail) Copyright 1987-2012, Larry Wall Binary build 1603 [296746] provided by ActiveState http://www.ActiveState.com Built Mar 13 2013 11:29:21 Perl may be copied only under the terms of either the Artistic License or the GNU General Public License, which may be found in the Perl 5 source kit. Complete documentation for Perl, including FAQ lists, should be found on this system using "man perl" or "perldoc perl". If you have access to the Internet, point your browser at http://www.perl.org/, the Perl Home Page. C:\Perl\perl>type utf8_unireg2.pl #! /bin/perl # # utf8_unireg.pl use 5.010; use strict; use warnings; use utf8; binmode STDOUT, ":encoding(shift_jis)"; my $str = "a:b:c:"; say join "|", ($str =~ /\p{AsciiAlpha}/g); sub AsciiAlpha { return <<END; 0041 005A # A-Z 0061 007A # a-z END } C:\Perl\perl>perl utf8_unireg2.pl Can't find Unicode property definition "AsciiAlpha" at utf8_unireg2.pl line 13. C:\Perl\perl>type utf8_unireg2.pl #! /bin/perl # # utf8_unireg.pl use 5.010; use strict; use warnings; use utf8; binmode STDOUT, ":encoding(shift_jis)"; my $str = "a:b:c:"; say join "|", ($str =~ /\p{IsAsciiAlpha}/g); sub IsAsciiAlpha { return <<END; 0041 005A # A-Z 0061 007A # a-z END } C:\Perl\perl>perl utf8_unireg2.pl a|b|c ★ 昔動いたプログラムが動かなくなったので、Perlの仕様変更でしょうね。。 ありがとうございました。