• ベストアンサー

Perlで任意の文字列同士を比較、共通項の有無を確認したい。

Perlの勉強中です。任意の2つの文字列を比較して部分的に共通する部分があるか判断したいのですがそんな方関数はありますか? 例えば「yakiniku」と「ikayakisoba」ですと「yaki」がもっとも長い共通部分として返してほしいわけです。 両者ともその都度不特定の「任意の」文字列といったところがポイントです。一方が特定の文字列なら簡単なのでしょうが・・・ お詳しい方よろしくお願いいたします。 m(_"_)m

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

  • ベストアンサー
  • taseki
  • ベストアンサー率66% (155/233)
回答No.1

いまいち自信ないですが…。 まず以下のように考えてみました。 含まれていない文字、たとえばタブ文字は含まれていない前提とします(ヌルなどでも良いかも)。 で、それを区切り文字として2つをつなげてます。 そして最長マッチの法則を利用して、 $match = ("$text1\t$text2" =~ /[^\t]*?([^\t]+)[^\t]*?\t.*?\1.*?/) ? $1 : ''; でやってみると、一見うまくいったように見えましたが、よく考えたら左から探していってマッチしてしまった時点で、それ以上長い文字を探すことをやめてしまう、ということに気付きました。 たとえば「unadon」と「tendon」だと、「don」ではなく「n」でマッチしてしまいます。 で、結局ループを使って文字長から順に最長マッチを探す方法しか思いつきませんでした…。 それを関数として定義すると、以下のような感じです。 $text1 = 'yakiniku'; $text2 = 'ikayakisoba'; $match = &text_match($text1, $text2); print $match; # --------------------------------- sub text_match { my ($text1, $text2) = @_; my $len = (length($text1) > length($text2)) ? length($text1) : length($text2); my $match; for (1; $len > 0; $len--) { if ("$text1\t$text2" =~ /[^\t]*?([^\t]{$len})[^\t]*?\t.*?\1.*?/) { $match = $1; last;} } return $match; }

takosuke88
質問者

お礼

なるほど!がっちり動きますね。 初心者なので一部意味がわかりませんでしたが、使えそうです。しかしやっぱり用意された関数はないのですね? ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (1)

  • bender
  • ベストアンサー率45% (108/236)
回答No.2

すでに簡潔な回答が寄せられているのですが、この問題は「最長共通文字列」を探す問題と似ているので、以下のような方法が効率がよいと思いました。 まず問題としては、文字列1の i 番目の文字と文字列2の j 番目の文字からそれぞれ始めて、共通する最長の文字列が何文字になるかを確認して、そのような共通文字列の中で最も長いものを返すような i, j の組み合わせを、すべての可能なi, j の組み合わせの中から探す、ということだと思います。 i, j についていえば、文字列1と2を含む Perl 変数をそれぞれ $s1, $s2 とすると、その範囲はそれぞれ 1<= i <= length($s1)、1<= j <= length($s2) になります。 ところで、ある i, j の組み合わせについては最長文字列の長さが仮に k と分かっているとき、組み合わせi-1, j-1から始まる最長文字列の長さは、文字列1の(i-1)番目と文字列2の(j-1)番目の文字が同じであれば k+1、そうでなければ 0 とすぐにわかるので、実は、このようにすでにわかっている情報を用いることで length($s1) * length($s2) 回の確認でこの作業をすませることができることになります。 ということで、以下のような手続きを書いてみました。 ($text1, $text2) = ("oomori-yakiniku","niku-yakisoba"); print &text_match($text1,$text2); sub text_match { @s1=split(//,$_[0]); @s2=split(//,$_[1]); $match=””; foreach $i (reverse (0..$#s1)) { foreach $j (reverse (0..$#s2)) { if($s1[$i] eq $s2[$j]) { $c{join(",",($i,$j))}=$c{join(",",($i+1,$j+1))}+1; $match=join("",@s1[$i..($i+$c{join(",",($i,$j))}-1)]) if($c{join(",",($i,$j))}>length($match)); } } } return $match; }

takosuke88
質問者

お礼

詳細な回答ありがとうございました。 試してみます!

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • [初心者]perlで文字列抽出

    perlの超初心者です. 標準出力された文字の中から任意の文字列をperlで抽出したいのですが... 例えば, 1 lsコマンドでファイル一覧を表示 2 表示された中から任意の文字列とマッチするものを抽出 3 マッチした文字列の後ろの文字を知る(拡張子とか) 4 さらに,1~3を'perl hoge.pl'とコマンド打つだけのワンアクションでやりたい. という感じなのですが... 勉強を始めたばかりなので,どういったキーワードを勉強すればよいのか,見当つかない状態です... おそらく,私がしょうもない質問をしているのだろうとは思いますが, 何かヒントでも教えていただければ幸いです. 周りに詳しい人物もいないので,なんとか頑張って習得したいと思っています. よろしくお願いしますm(><)m

    • ベストアンサー
    • Perl
  • 共通の文字列を取り出す方法

    PHP5.2.4を使用しています。 例えば、 /uri1/uri2/aaa /uri1/uri2/bb という2つの文字列の共通部分(この場合だと /uri1/uri2/)を 取り出したいのですが、どのような処理になるのでしょうか? またはそういう関数は既にあるのでしょうか?

    • ベストアンサー
    • PHP
  • perlでの比較について

    perlでの比較について Perlで以下のことをしたいと考えております。 ”文字列全一覧”の中に文字列が数千個ほど並んでいます。 文字列が数百個かいてあるテキストファイルが数百個ほどあります。 その文字列のテキストファイルに書かれている文字列全てが”文字列全一覧”の中にある文字列と 完全一致しているか、完全不一致している、部分一致しているか仕分けたいです。 【文字列全一覧】 ABC XYZ AAA ccc DADA ABCDEFG 【文字列ファイル1】 AAA bbbb xyz SSSSSS 【文字列ファイル2】 AAA ccc DADA 【文字列ファイル3】 ABCDGHJ XYZ AAA ABC 【文字列ファイル4】 ZZZZZZ llllll 5678901 KIKIKIKI 【文字列ファイル・・・】 ・・・・・ ・・・・・ このような感じでファイルがあります。(ちなみに上記の場合、”文字列ファイル2”が完全一致で”文字列ファイル4”が完全不一致、”文字列ファイル1”と”文字列ファイル3”が部分一致になります。) どなたか教えていただけないでしょうか(涙)

    • ベストアンサー
    • Perl
  • 文字列比較の演算子

    Perl の世界から PHP にやってまいりました。 Perl では、文字列の比較には専用の演算子がありまして、 str1 eq str2 とすると、二つの文字列が同値かどうか調べられますが、PHP にはこのような演算子はないのでしょうか? www.php.net のマニュアルを見ても、そのような演算子がありません。 == 演算子が使えるものかと <?php $str1 = "this is string" ; $str2 = "this is string" if( $str1 == $str2 ) { echo "two string is same" ; } ?> などを試してみるとうまくいくようですが、www.php.net のマニュアルには「文字列を数値化して比較する」と書いてあり、本当に文字列比較が出来るか確信がもてず…。 結局、文字列を比較したいときには strcmp を呼び出していますが、これは PHP 的には正しいのでしょうか?

    • ベストアンサー
    • PHP
  • Perlの文字列処理関数?

    Perl5.8も視野にいれた、便利な文字列関数を探しています。 trim rtrim ltrimを行う関数ですが、こういうものは自作するべきでしょうか? VBやPHPには標準であるようですが、Perlは文字コードを備えた一般的なものは 存在するのでしょうか?

    • ベストアンサー
    • Perl
  • Perlでの文字列置換に関して

    Perlでの文字列置換についてうかがいます。 文字列中からHTMLタグを排除しようと思うのですが、 タグ部分のみをうまく指定することができず、困っています。 どうか御知恵をお貸し下さい。

    • ベストアンサー
    • Perl
  • 2つの文字列にある数値(言葉)の共通項を抽出する関数はありますか?

    2つの文字列にある数値(言葉)の共通項を抽出する関数はありますか? 例えば2つの住所録でダブる住所を抽出する、というような関数はありますか? あるとしたらどう使えばいいでしょうか?

  • 文字列を比較するプログラム

    キーボードより文字列aと文字列bを入力し、比較する(どちらが辞書並びで先かを表示する)プログラムを作れ。但し、strcmp関数を用いてはならない。 という問題があるんですが文字列の比較のしかたがまったくわかりません。わかりやすく教えていただけるとありがたいです。

  • 文字列の比較について

    お世話になります。 次のような文字列の比較を考えているのですが 123456789 123456ABC89 この場合、ABCを7に置き換えると文字列が一致する ので、「7」と「ABC」を取り出したいのですが、 どのように調べたらよいでしょうか? VBはいろいろと関数も用意されているので、現在は instrとinstrrevを使って相違のある場所を調べようと していますがなかなか思うようにいきません。 お願いします。

  • 任意の文字列で置換するダイアログ

    シート内の関数に記載されている「item」という文字列を 任意に置換するダイアログの作り方で困っております。 シート内には 「='C:\sales\[item.xls]id'!$F$48=0,"",'C:\sales\[item.xls]id'!$F$48))] という関数が入っており、 この「item」を「1200」や「1800」など任意の文字列をインプットボックスに入力し (itemから任意の文字列に)『すべて置換』したいと思っております。 どなたかご存知の方がおいででしたら、ご教示くださいますようお願いいたします。