• ベストアンサー

正規表現でのエラー

検索システムを作ろうと思っています。テキストファイル(このソースでは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"; } }

  • Perl
  • 回答数7
  • ありがとう数7

質問者が選んだベストアンサー

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.5

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 プラグマを使うという方法もありますが、 問題を起こしやすいのでお勧めしません。

tokko64
質問者

補足

上記のスクリプトで試してみましたが、 Undefined subroutine &Encode::decode called at Z:\a.pl line 7, <> line 1. というエラーが出てスクリプトがうまく動きませんでした。sakusaker7さんは、うまく動くことができたのでしょうか?encodeというものが調べていくうちに多少はわかったのですが、どういうふうにモジュールをつけたら良いのかわかりません…。引き続きご回答をいただきたいと思います。

その他の回答 (6)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.7

んーエラーが再現しません。 スクリプトは 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 オプションを指定して実行してみてください。 何か警告は出てきませんか?

tokko64
質問者

お礼

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

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.6

すみません。スクリプトをコピーするときに一行抜けてしまったようです。 スクリプトの先頭に use Encode; という行を加えてください。 これでコンパイルが通るようになるはずです。

tokko64
質問者

お礼

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

tokko64
質問者

補足

お礼を投稿しておいて申し訳ないのですが、今度は日本語のデータが検索できなくなってしまいました。ファイルオープンに使っている「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. といったようなエラーが出てきます。これを改善することは可能でしょうか?何度もすみません。お手数おかけしますがお願いします。

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.4

ああ、大文字じゃなくて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> これも消えます。

tokko64
質問者

お礼

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

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.3

うまくいかないという具体例を挙げてもらえませんか? スクリプトと補足された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 スクリプトにちょっとまずいところはありますが、問題点が明らかに なっていないのでとりあえずは指摘しないでおきます。

tokko64
質問者

補足

私の場合では、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です。

  • guci-ok
  • ベストアンサー率33% (49/146)
回答No.2

キーボード入力で指定するのは、正規表現ですか、マッチさせたいテキストですか?  後者ならquotemeta関数を通します。 $kensaku = <>; chomp $kensaku; $ans = quotemeta($kensaku);

tokko64
質問者

お礼

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

tokko64
質問者

補足

すみません、さっきのでいちおう解決はしたんですが、日本語の文章も検索させて見ようと思い、「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」は「シ」にヒットしてしまうようです。どうしてこのようなことが起こるのでしょうか?また、この問題を解決するにはどうしたらいいのでしょうか?一度解決させていただいたのに、何度も質問をして申し訳ありませんが教えていただけないでしょうか。お願いします。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

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

tokko64
質問者

補足

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

関連するQ&A

  • 正規表現について2

    すみません、前回「正規表現について」でお世話になりました者です。 前回の分は解決したのですが、それに関連してもう少し教えてください。 data.txt---------------------------------------- aaabbbccc aaadddccc aaaeeeccc ------------------------------------------------ test.pl----------------------------------------- #!C:\Perl\bin\perl use CGI; my $q = CGI->new; $q->charset('Shift_JIS'); print $q->header(-type => "text/html"); my $line=0; open(IN,"<data.txt"); open(OUT,">output.txt"); while(<IN>){ if ($line++==0){ $output1="$1" if/aaa(.*?)ccc/;} s/aaa(.*)ccc/$1/ if (?aaa(.*)ccc?); print OUT; } close(OUT); close(IN); print $output1; ------------------------------------------------ とすることで、得られたい結果である、 output.txt-------------------------------------- bbb aaadddccc aaaeeeccc ------------------------------------------------ IEでの表示-------------------------------------- bbb ------------------------------------------------ となりました。そこで今回教えていただきたいのは、 data.txt---------------------------------------- <空行> aaabbbccc aaadddccc aaaeeeccc ------------------------------------------------ というようにdata.txtのはじめが空行の場合にも、 上記と同じような結果を得たいです。output.txtの はじめは空行になっても構いません。得られる文字として、上と同じ結果がほしいです。どうしたらよいでしょうか?よろしくお願いします。

    • ベストアンサー
    • Perl
  • Perlの正規表現

    Perlの正規表現で質問です。 例えば、 "aabbccddee"と"cdde"という2種の文字列があるとして"cdde"だけを検索(または置換)したい場合の正規表現ってどのようにすればよいのでしょうか? いま、"cdde"で検索すると"aabbccddee"と"cdde"の2種類がヒットしてしまうのですが"cdde"だけヒットするような正規表現をどなたかご教示ください。 宜しくお願い致します。

    • ベストアンサー
    • Perl
  • 正規表現での$1や$2の使用方法

    正規表現の置き換え文字列部分で使用できる$1や$2の使用方法を教えてください! 以下のソース1のようにs///gの置き換え文字列部分に$1や$2を直接記述すれば、1つ目と2つ目のマッチ部分で置換が行われるのは確認しました。 しかし、ソース2のように置き換え文字列部分を変数に代入したのち、使用すると、正しく置換が行われません。 $1や$2を含んだ置き換え文字列を変数に持っている状態で、ソース1と同じ結果を得るにはどうしたらよいか、ご存知でしたら教えて下さい。 ############################## # ソース1 ############################## #!/usr/bin/perl $data = '1234567'; $ptn = '(\d{3})(\d{4})'; $data =~ s/$ptn/$1-$2/g; ############################## ↓ $dataは123-4567となる。 ############################## # ソース2 ############################## #!/usr/bin/perl $data = '1234567'; $ptn = '(\d{3})(\d{4})'; $str = "$1-$2"; $data =~ s/$ptn/$str/g; ############################## ↓ $dataは-となる。

    • ベストアンサー
    • Perl
  • 正規表現による検索

    正規表現によって文字列を検索し、該当する文字列が存在する場合には存在する旨のメッセージを出力し、存在しない場合には存在しない旨のメッセージを出力するようなプログラムを作りたいのですが現在うまくいっておりません。ソースは以下になります。 #!/usr/bin/perl $logfile = './log_euc.log'; # ログファイル @logs = &read_file($logfile); foreach $log (@logs) { if ($log = ~/hogehoge/ ){ $log_stg = " 変数に文字列hogehogeは含まれています。 "; }else{ $log_stg = " 変数に文字列hogehogeは含まれていません。 "; } print " 判定結果\n "; print " $log_stg\n "; } sub read_file { local($logfile) = $_[0]; open(IN,$logfile); local(@files) = <IN>; close(IN); return @files; } 検索対象のファイル「log_euc.log」は以下です。 hogehoge mugemuge riri ari siri siursoiu sojowijugo hfsoiehrohogehoge sjhoisjofhoge osihojfhoge hsoghsoehogehogesoijggggg 検索結果は以下です。 判定結果 変数に文字列hogehogeは含まれています。 判定結果 変数に文字列hogehogeは含まれています。 判定結果 変数に文字列hogehogeは含まれています。 判定結果 変数に文字列hogehogeは含まれています。 判定結果 変数に文字列hogehogeは含まれています。 判定結果 変数に文字列hogehogeは含まれています。 判定結果 変数に文字列hogehogeは含まれています。 判定結果 変数に文字列hogehogeは含まれています。 判定結果 変数に文字列hogehogeは含まれています。 判定結果 変数に文字列hogehogeは含まれています。 判定結果 変数に文字列hogehogeは含まれています。

    • ベストアンサー
    • Perl
  • 正規表現について

    正規表現につての質問です。 今テキストファイルに下記のような漢字と数字が並んでいます。 そこから、漢字一文字だけの行を抜き出してきたいのですが、うまくいきません。PerlとCygwinを使用しています。よろしくお願いします。 人584504122 情報542701982 商品510342870 日414551872 方347990908 者347069359 中339925319 表示330177395 的324961911 私323727263 検索291502623 見ル285226619 場合275698771 一256241900 利用253752129 年240881734 時239273060 前228762989 店225241510 登録224560617   ・   ・    ・ プログラム中身 #! /usr/bin/perl -w #テキストから指定した単語などとマッチすると、 #その単語を含んだ文を抜き出してくる。 while(<>){ s/ +//g; s/\s+//g; if(/^([亜-煕]|[一-龠]){1}[0-9]*/){ print; print "\n"; } }

  • use encodingによって正規表現の結果が変わる?

    お世話になります。 webシステムで、画面入力値のチェックをperlで行っているのですが、 今回、perlのバージョンアップ対応を行っており、ソース修正をしたところ、以下のような現象に悩まされて困っております。 (本当のソースはもっと長いのですが、以下の現象により入力チェックが正常に動作しないという点までは突き止めました。) バージョン perl v5.8.0 os Red Hat Linux release 9 現象 use encodingが指定されていると、正規表現の$が効かないようです。 ソースと実行結果1 #!/usr/bin/perl #use encoding "euc-jp"; if ('apple' =~ /e$/) { print ("match\n"); } else { print ("unmatch\n"); } このときは match と表示されます。 ソースと実行結果2 #!/usr/bin/perl use encoding "euc-jp"; if ('apple' =~ /e$/) { print ("match\n"); } else { print ("unmatch\n"); } このときは、unmatch と表示されます。 対処方法のヒントだけでも頂けると助かります。 (他の質問を検索してみましたが、同様なものを見つけることができませんでした。) もしかして、perlのバグなのでしょうか?

    • ベストアンサー
    • Perl
  • 正規表現

    Java 5.1 java.util.regex.Pattern java.util.regex.Matcher を用いてHTMLのTABLEを抽出したいのですが、ヒットしません。正規表現のパターンはどうしたらいいのでしょう? パターン: < *table.*?>[\s.]*?< */table *?> 検索対象: … <table border=1 width=200> <tr><th>AA</th><th>BB</th></tr> <tr><td>CC</td><td>DD</td></tr> <tr><td>EE</td><td>FF</td></tr> </table> … で、TABLEタグを含むTABLE全体を期待したのですが全くヒットしませんでした。 ちなみに * <table …>と</table>単体ではヒットします。 * ソースから改行文字を取り除いて一行テキストとした場合にはヒットします。 これらのことから、改行文字がマッチしていないことが原因かと思うのですが、パターンの正規表現についてご教授願います。

    • ベストアンサー
    • Java
  • perl 計算結果をファイルへ出力したい

    perl やり始めたばかりです。宜しくお願いします。 入力ファイル data.txt があるとします。 data.txt は、 123 456 789 333 555 777 以上のようなテキストファイルといたします。このファイルを 以下の様に100分の1にして出力したい。 1.23 4.56 7.89 3.33 5.55 7.77 と言うことで、この場で教えていただきました。それが、以下です。 #!/usr/bin/perl open(IN, "data.txt") or die ; @x = <IN>; close (IN); foreach $line (@x){ chomp($line); @elms = split(' ',$line); foreach $data (@elms){ print $data/100," "; } print "\n"; } おかげ様でこれはこれで上手く動きました。そこで、出力値をファイルに 書き込みたいのです。 もちろん、以下の様な方法でファイルに 書き込めるのは判っております。 計算プログラム.pl > outfile.txt しかし、上のプログラムをベースにファイルに書き込めないかと色々と 試してはみましたが、どうも上手く行きません。 どなたか教えて頂けないでしょうか? 宜しくお願い申し上げます。

    • ベストアンサー
    • Perl
  • Perlを使った正規表現について

    テキストファイルを読み込んで、以下のルールに従った文字列だけを.txtで出力するプログラムを書いています。 具体的にはテキストファイル中の "text":"★★★","to_user" で囲まれている★★★の部分のみを抽出したいです。 そこで正規表現に触りだしたのですが、表現がうまくいっていないようで1週間ほどはまっています。。うまく出力できるように直しをいただけないでしょうか。 打ち明けてしまうと、★★★の部分はtwitterの呟き(日本語)になります。 以下がそのソースになります。よろしくお願いします。 print "Input file name: "; $ifname = <STDIN>; open(IN, $ifname); open(OUT, "> out.txt"); #出力ファイル while(<IN>){ if($ifname =" m/"test":(.*?),"to_user"/; next if($_ eq ""); print OUT "$_\n"; #書き出し } close(OUT); close(IN);

    • ベストアンサー
    • Perl
  • 正規表現で「)」がメタ文字の理由?

    Perlの正規表現で、「)」(カッコ閉じ)は、「(」(カッコ開け)同様メタ文字で、もし/)/のようなマッチ演算子を書いて、「)」という文字列を検索しようとすると、Unmatched ) in regexというエラーになります。 しかし、「]」(角カッコ閉じ)や、「}」(中かっこ閉じ)は、メタ文字ではなく、/]/、/}/のようなマッチ演算子は正当で、それぞれ]、}をきちんと検索するのです。 「[」(角カッコ開け、文字クラスを作る)や、「{」(中かっこ開け)はメタ文字なのに、です。 開けがこないのに閉じが来た場合、]と}はエラーにならないのに、)だけはエラーになります。 これは、なぜでしょうか。

    • ベストアンサー
    • Perl

専門家に質問してみよう