- 締切済み
テキストファイル内を行単位でAND検索し表示したい
perl初心者です。 フォームより受け取った複数の文字列をキーとして配列[@keywords]に格納し、 テキストファイル内を行単位でAND検索し結果を表示したいです。 OR検索は 検索対象文字が"a","b","c"の場合、$key = a|b|c と生成してうまく表示出来ているようなのですが、 AND検索をする場合はどの様に$keyを生成すればよいか教えて頂けないでしょうか。 よろしくお願い致します。 my $key = ""; if($option eq "or"){ #OR検索key生成 for(my $i = 0; $i < @keywords; $i++){ if($i != 0){$key = $key . "|";} $key = $key . @keywords[$i]; } else { #AND検索key生成 #ここの部分がどの様に書いたらいいかわかりません。 } #検索開始 my $result = ""; if (open(F, $SEARCH_FILE)) { if ($key !~ /^\s*$/) { while (<F>) { if (s|($key)|<font color="red">$1</font>|gi) { $result .= $_; } } #検索文字が見つからない時の表示 if ($result eq ""){ $result = "NOT FOUND" } } print "<pre>$result</pre>\n"; close(F); } else { #検索対象となるファイルが見つからない時のエラー表示 print "ERROR: Can't open '$SEARCH_FILE'\n"; }
- みんなの回答 (5)
- 専門家の回答
みんなの回答
- SE-1
- ベストアンサー率57% (26/45)
# まちがえました・・・ 前の投稿は忘れてください・・・ my $key = join("|", @keywords); my $result = ""; if (open(F, $SEARCH_FILE)) { if ($key !~ /^\s*$/) { LABEL: while (<F>) { if($option eq "or"){ if (s|($key)|<font color="red">$1</font>|gi) { $result .= $_; } } else { foreach my $keyword (@keywords){ $_ =~ s/($keyword)/<font color=\"red\">$1<\/font>/ ? 1 : next LABEL ; } $result .= $_; } } if ($result eq ""){ $result = "NOT FOUND" } } print "<pre>$result</pre>\n"; close(F); } else { print "ERROR: Can't open '$SEARCH_FILE'\n"; }
- SE-1
- ベストアンサー率57% (26/45)
# 実際のファイルで試してみないとご希望通りに動くか自信がないのですが・・ # 16 行目を LABEL: while (<F>) { として、 # "ここの部分がどの様に書いたらいいかわかりません。" の部分を以下のコードに変えてみてください。 foreach my $keyword (@keywords){ $_ =~ s/($keyword)/<font color=\"red\">$1<\/font>/ ? 1 : next LABEL ; } $result .= $_;
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
>条件式を動的に作る事は可能でしょうか? 質問文のプログラムの場合、マッチした場合のキーワードを赤字にする処理とマッチが兼ねているので、そのまま$key をAND 検索用に作成して利用することはできません。 1つの方法として、修正したサンプルを作ってみました。 ---------------------------------------------------------------- sub andMatch { my @list = @_; return sub { my $str = shift; foreach my $re (@list){ return 0 unless $str =~ /$re/i; } return 1; } } my $key = join("|", @keywords); my $test = andMatch(@keywords); #検索開始 my $result = ""; if (open(F, $SEARCH_FILE)) { if ($key !~ /^\s*$/) { while (<F>) { if($option eq "or"){ if (s|($key)|<font color="red">$1</font>|gi) { $result .= $_; } } else { if(&$test($_)){ $_ =~ s|($key)|<font color="red">$1</font>|gi; $result .= $_; } } } #検索文字が見つからない時の表示 if ($result eq ""){ $result = "NOT FOUND" } } print "<pre>$result</pre>\n"; close(F); } else { #検索対象となるファイルが見つからない時のエラー表示 print "ERROR: Can't open '$SEARCH_FILE'\n"; }
お礼
たびたびの質問に早々にご回答頂きありがとうございます。 ご親切にソースを書いて頂きましたので、意味もよくわからないままコピーさせて頂いた結果、希望通りの検索が出来ました。 今度の土日にでも、頂いたソースを元に勉強します。 本当は自分で勉強して解決すべき事なのでしょうが、今回の件ではずいぶん考えても解決出来ず投稿いたしました。 お忙しい中、ご親切にご回答頂き本当にありがとうございました。
- SE-1
- ベストアンサー率57% (26/45)
# こんなんどうでしょう。 # Perl クックブックでも2つ以上の AND 検索を紹介していないとこをみると、#1 さんのおっしゃるように正規表現では効率が落ちてしまうということなんでしょうね。 my @keywords = qw / def 789 abc /; LABEL: foreach my $line (<DATA>){ my $cnt=0; $line =~ s/($_)/#$1#/ ? $cnt++ : next LABEL foreach @keywords; print "$line" if $cnt == @keywords; } __DATA__ abc 123 def 456 ghi 789 jkl 012 mno 345 pqr 678 789 abc def 456 ghi 555
お礼
ご回答頂きありがとうございます。 今、会社で読ませて頂いています。 手元に参考書がなく、書いて頂いたソースを完全に理解出来ていませんので、帰宅後に使用させて頂きます。 まずはお礼かたがたご挨拶申し上げます。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
AND 条件を満たすようなパターンを作成しようとするより $string =~ /パターン1/ && $string =~ /パターン2/ … のような条件式にする(または条件式を作りあとから評価する)か ループにする方が 簡単明瞭でかつ効率も良いです。
補足
早々のご回答ありがとうございます。 ご回答頂いた内容について質問なのですが、 条件式を動的に作る事は可能でしょうか? フォームより受け取る検索対象となる文字列の数は、テキストフォーム内でスペースで区切られた任意の数となる為、 >$string =~ /パターン1/ && $string =~ /パターン2/ … 文字列の数に応じて条件式を動的に作る事になると思うのですが・・・ 的外れな質問でしたら申し訳ありません。 perl初心者で、わからない事が多くて・・・ ご教授お願い致します。
お礼
お忙しい中、度々ご回答頂き感謝致します。 頂いたソースを参考書片手に勉強します。 今回の件は、SE-1さん、BLUEPIXYさんのおかげで解決する事が出来ました。 本当にありがとうございました。