プロが教える店舗&オフィスのセキュリティ対策術

検索システムを作ろうと思っています。テキストファイル(このソースではgreetings.txtです。)の中にある文章をキーボード入力で1文字でもヒットすれば抜き取って表示させたいのですが、以下のソースをコマンドプロンプトで実験したところ「Q、Y,S,M、と記号」で検索すると全ての文章がヒットしてしまいます。他の文字では問題無くヒットするのですが…。perlを始めてばかりでまだまだわからないことだらけです。いちおう本やネットで検索したんですがさっぱりわかりません。どなたかどうかお力を貸していただけませんか?

#!C:\Perl\bin\perl

$kensaku = <>;
$ans = eval $kensaku;

open(IN, "greetings.txt");
while ($line = <IN>){
if($line =~ /$ans/i){
print "$line";
}
}

A 回答 (7件)

Perlはそのままでは日本語(をあらわす文字コード)を理解しません。


そのため、

>for %i in (オ ツ イ シ) do echo %i | hexdump
00000000: 83 49 20 0A .I .
00000000: 83 63 20 0A .c .
00000000: 83 43 20 0A .C .
00000000: 83 56 20 0A .V .

オ、ツ、イ、シのそれぞれにI, c, C, Vを見つけてしまいます。
この問題はPerlに日本語文字コードを理解させればいいので、
たとえば以下のようにスクリプトを書き換えます。

$kensaku = <>;
$ans = $kensaku;
chomp $ans;

$ans = Encode::decode('sjis', $ans);

open(IN, '<:encoding(sjis)', "greetings.txt") or die "can't open data file\n";
while ($line = <IN>){
chomp $line;
if($line =~ /$ans/i){
$line = Encode::encode('sjis', $line);
print $line, "\n";
}
}

use encoding プラグマを使うという方法もありますが、
問題を起こしやすいのでお勧めしません。

この回答への補足

上記のスクリプトで試してみましたが、

Undefined subroutine &Encode::decode called at Z:\a.pl line 7, <> line 1.

というエラーが出てスクリプトがうまく動きませんでした。sakusaker7さんは、うまく動くことができたのでしょうか?encodeというものが調べていくうちに多少はわかったのですが、どういうふうにモジュールをつけたら良いのかわかりません…。引き続きご回答をいただきたいと思います。

補足日時:2006/12/05 17:40
    • good
    • 0

んーエラーが再現しません。



スクリプトは
use Encode;

$kensaku = <>;
$ans = $kensaku;
chomp $ans;

$ans = Encode::decode('sjis', $ans);

open(IN, '<:encoding(sjis)', "greetings.txt") or die "can't open data file
\n";
while ($line = <IN>){
chomp $line;
if($line =~ /$ans/i){
$line = Encode::encode('sjis', $line);
print $line, "\n";
}
}
__END__
$kensaku = <>;
#$ans = eval $kensaku;
$ans = $kensaku;

open(IN, "greetings.txt");
while ($line = <IN>){
if($line =~ /$ans/i){
print "$line";
}
}

で、greetings.txtは以下の通り
湘南乃風
KREVA
monkey Majik
ACIDMAN
175R
ケツメイシ
レミオロメン
大塚愛

以下実行例です。

D:\work\script\perl>perl find.pl

大塚愛

D:\work\script\perl>perl find.pl

ケツメイシ

D:\work\script\perl>perl find.pl

湘南乃風

perl -w スクリプト名 のように -w オプションを指定して実行してみてください。
何か警告は出てきませんか?
    • good
    • 0
この回答へのお礼

すみません。スクリプトにちょっと余計なものを打ち込んでしまったみたいです…。コピペしてみたら普通に動作しました^^;申し訳ないです。お手数おかけしてすみませんでした。何回もご親切に教えてくださって本当に感謝しています。また何かあればここに来ようと思います。

お礼日時:2006/12/06 08:48

すみません。

スクリプトをコピーするときに一行抜けてしまったようです。
スクリプトの先頭に

use Encode;

という行を加えてください。
これでコンパイルが通るようになるはずです。

この回答への補足

お礼を投稿しておいて申し訳ないのですが、今度は日本語のデータが検索できなくなってしまいました。ファイルオープンに使っている「greetings.txt」には、

湘南乃風
KREVA
monkey Majik
ACIDMAN
175R
ケツメイシ
レミオロメン
大塚愛

という日本語を含んだ文字列が含まれているのですが、これを検索しようとすると、

F:\perl>perl sisaku.pl

Quantifier follows nothing in regex; marked by <-- HERE in m/? <-- HERE ?/ at si
saku.pl line 14, <IN> line 1.

F:\perl>perl sisaku.pl

Quantifier follows nothing in regex; marked by <-- HERE in m/? <-- HERE ?/ at si
saku.pl line 14, <IN> line 1.

F:\perl>perl sisaku.pl

Quantifier follows nothing in regex; marked by <-- HERE in m/? <-- HERE P/ at si
saku.pl line 14, <IN> line 1.

といったようなエラーが出てきます。これを改善することは可能でしょうか?何度もすみません。お手数おかけしますがお願いします。

補足日時:2006/12/06 00:51
    • good
    • 0
この回答へのお礼

ありがとうございました。無事コンパイルも通り、正常にプログラムを動作させることができました!また何かわからないことがあれば質問させていただきます。本当にありがとうございました!

お礼日時:2006/12/06 00:45

ああ、大文字じゃなくてq,y,s,m は小文字なんですね。


わかりました。
これは
$ans = eval $kensaku;

でeval してるからです(なんのため?)
q, y, s, m はそれぞれ特別な意味を持つものなので、evalすると
消えてなくなるようです。
s は s///, y は y/// qは シングルクォートの代わりの記号の指定 mは m///
の指定に使われますから。

:\work\script\perl>perl -de 42
oading DB routines from perl5db.pl version 1.28
ditor support available.
nter h or `h h' for help, or `perldoc perldebug' for more help.

ain::(-e:1): 42
DB<1> print eval "q"
DB<2> print eval "@"
DB<3> print eval "Q"
Q

だから、
DB<4> print eval "tr"
DB<5>
これも消えます。
    • good
    • 0
この回答へのお礼

なるほど、そういうことだったんですか。どうもうまくいかないので本を読みあさっていた所、evalを使っている例文を見つけまして、適当にくっつけたところあんな感じで半分成功の半分失敗状態になってしまいました…。いや、意味がわかっていないのでは完全に失敗ですね;
わかりやすいご説明どうもありがとうございました!大変勉強になりました。ですが、この後また問題が起こりまして…。詳しいことは、guci-okさんへの補足に書いてあります。できればもう少し力を貸していただけませんか?お願いします。

お礼日時:2006/12/04 03:27

うまくいかないという具体例を挙げてもらえませんか?



スクリプトと補足されたgreetings.txt をそのままコピペして試してみましたが

D:\work\script\perl>perl err.pl
g
Good morning
good bye
good night

D:\work\script\perl>perl err.pl
Q

D:\work\script\perl>perl err.pl
a
thank you

スクリプトにちょっとまずいところはありますが、問題点が明らかに
なっていないのでとりあえずは指摘しないでおきます。

この回答への補足

私の場合では、Qと打ったところ、「greetings.txt」の全文が表示されてしまいました。具体的に申しますと

F:\perl>perl sisaku.pl
q
Good morning
hello
good bye
thank you
good night
F:\perl>perl sisaku.pl

F:\perl>perl sisaku.pl
y
Good morning
hello
good bye
thank you
good night

F:\perl>perl sisaku.pl
s
Good morning
hello
good bye
thank you
good night

F:\perl>perl sisaku.pl
m
Good morning
hello
good bye
thank you
good night

F:\perl>perl sisaku.pl
@
Good morning
hello
good bye
thank you
good night

のように、「Q、Y、S、M」と「記号」で入力すると、「greetings.txt」の中に「Q」は一つも入ってないはずなのに、「greetings.txt」の全文が表示されてしまいます。

ちなみに他の英数字で入力すると、ちゃんと期待通りの結果が返ってきます。

F:\perl>perl sisaku.pl
g
Good morning
good bye
good night

F:\perl>perl sisaku.pl
a
thank you

F:\perl>perl sisaku.pl
h
hello
thank you
good night

sakusaker7さんは、見たところ「Q」で入力しても何も表示されずうまくいっているみたいですね。なぜでしょうか?perlのバージョンの問題でしょうか?ちなみに使っているperlのバージョンは5.8です。

補足日時:2006/12/04 02:00
    • good
    • 0

キーボード入力で指定するのは、正規表現ですか、マッチさせたいテキストですか? 


後者ならquotemeta関数を通します。

$kensaku = <>;
chomp $kensaku;
$ans = quotemeta($kensaku);

この回答への補足

すみません、さっきのでいちおう解決はしたんですが、日本語の文章も検索させて見ようと思い、「greetings.txt」の内容を変更し、自分の知っている歌手などの名前を適当に入れてみました。内容はこうです。


greetings.txt

湘南乃風
KREVA
monkey Majik
ACIDMAN
175R
ケツメイシ
レミオロメン
大塚愛

これで動かしてみると「i」,「c」,「v」で入力して検索をかけたときになぜかカタカナのデータまで表示されてしまいます。実際の表示では、

F:\perl>perl sisaku.pl
i
monkey Majik
ACIDMAN
レミオロメン

F:\perl>perl sisaku.pl
c
ACIDMAN
ケツメイシ

F:\perl>perl sisaku.pl
v
KREVA
ケツメイシ

こんな感じです。調べてみたところ、「i」は「オ」に、「c」は「ツ」と「イ」に、「v」は「シ」にヒットしてしまうようです。どうしてこのようなことが起こるのでしょうか?また、この問題を解決するにはどうしたらいいのでしょうか?一度解決させていただいたのに、何度も質問をして申し訳ありませんが教えていただけないでしょうか。お願いします。

補足日時:2006/12/04 03:00
    • good
    • 0
この回答へのお礼

guci-okさんの言われたとおりにやってみたらちゃんと期待通りの結果が得られました!quotemeta関数を調べてみたところ、どうやら文字列中の記号が正規表現のメタ文字として扱われるのを防ぐものらしいですね。だから記号等で検索した場合、全文の内容を表示されてしまったんですね。以外とあっさりした解決で以外でした^^;
質問の内容に不足していた部分があるにもかかわらず教えてくださり、本当にどうもありがとうございました!また機会があれば質問させていただきたいと思います。

お礼日時:2006/12/04 02:27

greetings.txt の中身もわからんし「実際にはどのようにキーボードから入力したか」もわからんのだから, かなり回答しずらいんだけど...


ちなみに, なんで eval してるの?

この回答への補足

greetings.txtの内容は

Good morning
hello
good bye
thank you
good night

といったものです。例えばここから「g」とキーボードから入力することで「Good morning」「good bye」「good night」が表示されるようにしたいのです。「a」と入力すれば「thank you」が表示されたり。試行錯誤したのですが、ちゃんとした結果が得られません。引き続き回答お願いします。

補足日時:2006/12/03 18:42
    • good
    • 0

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