プロが教えるわが家の防犯対策術!

Perlに関していつもお世話になっております。
今回も正規表現に関する質問をしたいと思います。

「あ、あい、あいう、あいうえ、あいうえお」というハッシュが存在するときに、「{あ}は○○回出ました。」「{あい}は○○回出ました。」とそれぞれ表示させるコードを組もうと思います。

前回までで皆様に教えていただいたことを元に組んでみました。

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

my %word_of = (
'あい' => 0,
'あいう' => 0,
'あいうえ' => 0,
'あいうえお' => 0,
'かき' => 0,
'かきく' => 0,
'かきくけ' => 0,
'かきくけこ' => 0,
);

foreach my $search_key ( keys %word_of ) {
foreach my $word ( keys %word_of ) {
if ( $word =~ /$search_key/ ) {
$word_of{$search_key}++;
}
}
}

foreach my $key ( sort ( keys %word_of ) ) {

# utf8, shiftjis eucjp ...
print encode( 'utf8', "「$key」 は $word_of{$key} 回出ました" ),
"\n";
}

これを出来ればeucjpで組みたいのですが、可能でしょうか?
私の思いあたる点、utf8表記の部分をeucjpに直しただけではエラーが出てしまいます。

よろしくお願いします。

A 回答 (4件)

(1)何故あまりお勧めできないのでしょうか?


少し遠回りして話しましょう。
http://xiaoxia.exblog.jp/2290810/

http://kototubo.exblog.jp/2274040
などでも話題になったことがありますが、次のコードを見て下さい。

my $str = 'アは';
print $str, "\n";
my $del = '△';
print $del, "\n";
$str =~ s/$del//;
print $str, "\n";

このコードは文字列 $str に含まれる △ を削除するというものです。
これを euc-jp で保存し実行すると次ようになります。

アは



'アは' から '△' を削除すると 'ハ'が出てきました。
これは 'アは' が バイナリで見ると a5 a2 a4 cf であり、
'△' はバイナリで見ると、a2 a4です。
a5 a2 a4 cf から a2 a4 を削除すると、a5 cf になり、これは'ハ'になり
ます。したがって、日本語などのマルチバイトをそのまま、コード内で使
うことは、とても危ういことです。

では、次にuse encodingを使ってみましょう。

use encoding 'euc-jp';
my $str = 'アは';
print $str, "\n";
my $del = '△';
print $del, "\n";
$str =~ s/$del//;
print $str, "\n";

これを実行すると、
アは

アは
となり、期待した結果になります。

use encoding をすると何が起こるのでしょう。use encoding をすると、
実行時に Perl スクリプト内で使われるマルチバイト文字は、フラグ付き
UTF-8 (flagged UTF-8) に変換され、標準入出力はフラグ付き UTF-8 に自
動でエンコード、デコードされます。したがって、ユーザからは euc-jp で
コードを保存し、標準入力は euc-jp を受け取り、標準出力は euc-jp で出
力することになります。つまり、euc-jp でコードを書いて実行するだけで
ユーザは特に何も考える必要がなくなるのです。

しかし、Perl にとっては、UTF-8 がもっとも自然で楽なエンコード方式な
のです。したがって、Perl スクリプトは UTF-8 で書き、use utf8し、入
出力のときエンコード/デコードするのがお勧めです。
euc-jp の環境であれば、UTF-8 で書いて、以下のようにすれ標準入出力 を
euc-jp を自動でエンコード/デコードされます。

use utf8;
binmode STDOUT, ":encoding(eucjp)";
binmode STDIN, ":encoding(eucjp)";

euc-jpで書かれたファイルの場合は、
open my $fh, "<", $file or die "$file : $!";
binmode $fh, ":encoding(eucjp)";
あるいは
open my $fh, "<:encoding(eucjp)", $file or die "$file : $!";
などどすれば、euc-jp で書かれたファイルは、Perl で読むときは、フラグ
付き UTF-8 に自動で変換されます。これ以外にも Encode モジュールを
を使う方法もありますが、binmode で事足ることも多いでしょう。

(2)use strictは使用しないでも問題はありませんか?
use strict はチェッカとして役割があるので、通常は付けたほうがよいで
しょう。つぎのコードを見て下さい。

#!/usr/bin/perl
my $val = 'Yamada';
print "Konyaga $va1 da\n";

これを実行すると、
Konyaga da
と出力されます。

よく見るとわかりますが、$va1と$val は va'いち' と va'える'となってい
ます。use strict を付けるとこういった間違いを指摘してくれます。

use strict を付けるとなぜ動かないのか、少し調べたほうがよいと思いま
す。よくある間違いとしては、
・変数を 使用前に my (または our) で宣言していない
・ファイルハンドラを my (または our)で宣言していない
× open FH, "<", $file or die "$file : $!";
○ open my $fh, "<", $file or die "$file : $!";

また、CGI::Carp を使えば、ブラウザ上にエラー内容が表示されます。

#!/usr/bin/perl -T
use strict;
use warnings;
use CGI::Carp qw(fatalsToBrowser);

my $val = 'Yamada';
print "Konyaga $va1 da\n";

これをブラウザで開くと
Software error:
Global symbol "$va1" requires explicit package name at foo.cgi line 7.
となって、どこがおかしいかわかります。
    • good
    • 0
この回答へのお礼

回答ありがとうございます.
ご丁寧に説明していただき,とても感謝しております!

おかげですべての問題が解決し,プログラムも正常に動くようになりました.
ありがとうございました.

お礼日時:2009/09/06 10:50

use encodingがお薦めできない理由は、これがスコープをもっていないことと、


Perl IOレイヤーを勝手に操作することです。

自分の書いたソースファイルだけに影響を及ぼすだけならいいのですが、他の
ソースファイル(モジュール)を取り込んで利用するときに、そのソースファ
イルにまで影響が及びます。

詳しくは以下サイトをご覧ください。

[Perl] encoding プラグマについて
http://scape.blog.so-net.ne.jp/2008-09-06

参考URL:http://scape.blog.so-net.ne.jp/2008-09-06
    • good
    • 0
この回答へのお礼

回答ありがとうございます.
URLとても参考になりました!

お礼日時:2009/09/06 10:52

use encoding を使えばできます。

実はあまりお勧めしません。
ロジックは自分の趣味に合わせて変えてありますが、意味はありません。

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

# use encoding はレガシーな Perl スクリプトを動かすときのみ使用すること
# 通常は、utf-8 で保存し、use utf8 する
# http://blog.livedoor.jp/dankogai/archives/512217 …

# ソースを euc-jp で記述し、標準出力を shift-jis にする例
# 標準入出力も euc-jp であれば、use encoding 'euc-jp'; だけでよい。
use encoding 'euc-jp', STDOUT => 'shift-jis';

my %word_of = map { $_ => 0 } qw( あい
あいう
あいうえ
あいうえお
かき
かきく
かきくけ
かきくけこ );

foreach my $search_key ( keys %word_of ) {
foreach my $word ( keys %word_of ) {
$word_of{$search_key}++ if $word =~ /$search_key/;
}
}

print "「$_」 は $word_of{$_} 回出ました\n"
foreach ( sort ( keys %word_of ) );

この回答への補足

回答ありがとうございます。
早速実行してみようと思います!

2点ほどお尋ねします。
(1)何故あまりお勧めできないのでしょうか?
(2)use strictは使用しないでも問題はありませんか?

組み込みの際にどうしてもエラーが出てしまうため、ひとつひとつ確認していたのですが、use strictを実行したときにプログラムが正常に動かなくなってしまいます。
行数が多くて見落としているのが原因かもしれませんが、それ以外でuse strictを実行したときに正常に動かなくなる原因はあるのでしょうか?

初歩的なミスでしたら申し訳ありません。
頂いたプログラミングについて不明な点がありましたら、また伺う形になりますが、そのときはよろしくお願いいたします。

補足日時:2009/08/28 12:04
    • good
    • 0

・「eucjp で組みたい」とはどういうことでしょうか? 文字列を EUC で書きたい? 出力を EUC にしたい? その他?


・「utf8表記の部分をeucjpに直しただけではエラーが出る」というのは, 具体的にはどのようなプログラムにしたらどのようなエラーが出るのでしょうか?

この回答への補足

回答ありがとうございます。

>・「eucjp で組みたい」とはどういうことでしょうか? 文字列を EUC で書きたい? 出力を EUC にしたい? その他?
文字列をEUCで書きたいに該当します。
組み込もうとしているcgiの文字コード指定形式がEUCなのもあり、出来ればEUCで試みたいと思っております。

>・「utf8表記の部分をeucjpに直しただけではエラーが出る」というのは, 具体的にはどのようなプログラムにしたらどのようなエラーが出るのでしょうか?
上記に記載したコードについて、utf8表記の箇所を全てEUCに変換したところ、うまく動きませんでした。
その後utf8に文字コード指定をしたところ、コード自体が文字化けしてしまい、utf8での動作確認をすることが出来ませんでした。

また不明な点がございましたら、随時応答します。
Perlの扱いにまだ慣れてない部分がありまして、もしかしたら初歩的なミスをしているかもしれません。
申し訳ありませんが、よろしくお願いいたします。

補足日時:2009/08/28 11:51
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!