手直し依頼:n-gramのプログラミングで「可愛い」「あの子」「デートしたい」を結果に出力できない

このQ&Aのポイント
  • プログラミング歴3週間の私が作成したn-gramのプログラムが上手く動かないです。結果が「可愛い」「あの子」「デートしたい」になるように修正をお願いしたいです。
  • n-gramのプログラムを作成しましたが、結果が「可愛い」「あの子」「デートしたい」とならず、どなたか優秀な方に手直しのお願いをしたいです。
  • 私はプログラミング歴が3週間ですが、n-gramのプログラムを作成しました。しかし、結果が「可愛い」「あの子」「デートしたい」となりません。手直しをお願いしたいです。
回答を見る
  • ベストアンサー

n-gramの手直し

プログラミング歴3週間ですが、n-gramのプログラミングを 作ってみましたが、うまく動きません。結果が「可愛い」 「あの子」「デートしたい」とならないといけないののですが、 どなたか優秀な方に手直しをお願いしたいと思います。よろしく お願いいたします。 my $a = "可愛いあの子とデートがしたい"; my $b = "あの子可愛いよね。デートがしたい"; $len1 = length($a); $len2 = length($b); my $i = 0; while($i < $len1) { if (0 == ($i % 2)) { $re1 = substr($a, $i, 2); my $j = 0; while($j < $len2) { if(0 == ($j % 2)) { $re2 = substr($b, $j, 2); } $j++; if($re1 eq $re2) { @word1 = ("$re1"); $num1 = push(@words, @word1); $count++; last; } } } $i++; if(0 == ($i % 2)){ if($re1 ne $re2){ if($count > 0) { @word2 = ("\n"); $num2 = push(@words, @word2); $count = 0; } } } } my $rewords = join('', @words); print $rewords;

  • Perl
  • 回答数5
  • ありがとう数4

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

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

> 新たに作ってみたのですが、「あひる」までは拾ってくれるのですが、 > 「すき」を拾ってくれません。どなたか手直しお願いいたします。 #1の回答のスクリプトで得たい答えは求められるのに、 なぜわざわざ作り直した挙句に直してくれとか おねだりするんですか? n-gramも使ってないですよね? #!/usr/bin/perl use strict; use warnings; use strict; my $DEBUG=1; my $str1 = "あひるがすき"; my $str2 = "あひるはすき"; #my $str1 = "可愛いあの子とデートがしたい"; #my $str2 = "あの子可愛いよね。デートがしたい"; my $len1 = length $str1; my $len2 = length $str2; my @words; for (my $i=0; $i<$len1; $i+=2) { print "\$i=$i\n" if $DEBUG; my $try_len = 2; my $common = ""; while ($try_len <= $len2 - $i) { my $try = substr $str1, $i, $try_len; my $pos = index $str2, $try; print "\$try=$try, $pos\n" if $DEBUG; if ($pos<0) { print "break inner loop\n" if $DEBUG; last; } $common = $try; $try_len += 2; } if ($common ne '') { $i+=length($common)-2; push @words, $common; } } print join(':', @words);

funakata
質問者

お礼

これがn-gramなのですね。ありがとうございました。

funakata
質問者

補足

自分でも努力すべきだと思ったからです。

その他の回答 (4)

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

n-gramにずいぶんとご執心ですけど、結局のところなにがやりたいのでしょうか? 今回の例題から推測して、二つの文章を比較してできるだけ長い共通部分を 切り出すことが目的とも思えますが、だとすればそれのために n-gramを使うことはあまり適当ではないと思います。 Longest Common Sequence を求めるアルゴリズムを応用するとかしたほうが 効率がよいと思います。 文書比較アルゴリズム http://hp.vector.co.jp/authors/VA007799/viviProg/doc5.htm Longest common subsequence problem - Wikipedia, the free encyclopedia http://en.wikipedia.org/wiki/Longest_common_subsequence_problem n-gramそのものの資料のポインタはもう一つの質問の方で 書きましたのでこちらでは省略します。

funakata
質問者

補足

新たに作ってみたのですが、「あひる」までは拾ってくれるのですが、 「すき」を拾ってくれません。どなたか手直しお願いいたします。 my $a = "あひるがすき"; my $b = "あひるはすき"; my $len1 = length($a); my $len2 = length($b); my $i = 0; my $j = 0; while($len1 >= $i) { while($len2 >= $j) { print $i; print $j; if(0 == $i % 2) { if(0 == $j % 2) { my $word1 = substr($a, $i, $j + 2); my $word2 = substr($b, $i, $j + 2); if($word1 eq $word2) { my $len3 = length($word1); my $nextword=substr($word1, $even1, $len3); push(@lastwords, $nextword); } } } $j++; } $i++; } print $popwords = pop(@lastwords);

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

希望の結果は得られているようですけど、n-gramを使ってないのですが それはいいんでしょうか?

funakata
質問者

お礼

P.S.本でも可です。よろしくお願いいたします。

funakata
質問者

補足

実はn-gramなるものを良く理解していないので、もし良いサイトがあったらご紹介よろしくお願いいたします。とりあえず、これでいきます。。

  • moon_night
  • ベストアンサー率32% (598/1831)
回答No.2

追記。 my $a = "可愛いあの子とデートがしたい"; my $b = "あの子可愛いよね。デートがしたい"; とある場合、 $aの一文字目からHITがあるか調べていきます。 HITしたら、続いて二文字目もヒットがあるか調べます。 HITしたところまでの文字を取得して次の文字から調べます。 例) $bの中に$aの一文字目の「可」があるか調べる。 HITするので、$bの中に「可愛」がHITするか調べる。 HITするので、$bの中に「可愛い」」がHITするか調べる。 HITするので、$bの中に「可愛いあ」がHITするか調べる。 HITしないので、「可愛い」の文字を取得して、次の「あ」を調べることをする。 以下文字がなくなるまで上の繰り返し。

funakata
質問者

お礼

よく分かりました。自分なりにまた作ってみたいと思います。ありがとうございました。

  • moon_night
  • ベストアンサー率32% (598/1831)
回答No.1

少し意味がわかりません(定義が曖昧です)が、 >結果が「可愛い」「あの子」「デートしたい」 という結果が満たせればいいだけならば以下。 ご質問のプログラムは文字単位でしか調べてないので、単語単位ではHITしません。 my $a = "可愛いあの子とデートがしたい"; my $b = "あの子可愛いよね。デートがしたい"; $len1 = length($a); $len2 = length($b); my $i = 0; while($i < $len1) { my $j = 0; while(&tx($b,substr($a, $i, $j+2))>=0 and &tx($b,substr($a, $i, $j+2))+$j < $len2) { $j+=2; } if ($j) { push(@word, substr($a, $i, $j)); $i += $j; } else { $i += 2; } } sub tx { return index($_[0],$_[1]); } print join(',', @word);

funakata
質問者

お礼

見てもさっぱり分かりませんが、ご名答です。もっと勉強がんばります。ありがとうございました。もしアルゴリズムのご説明もいただけるようでしたら、お願いいたします。

関連するQ&A

  • POJ 2718

    #include <iostream> #include <cstdio> #include <algorithm> #include <vector> using namespace std; int numbers[10]; int length; int n; int permutation(int num[10]){ int i; int oneco=0; for(i=0;i<length;i++){ if(num[i]){oneco++;} } int length2 = length-oneco; if((oneco==length)||(oneco==0)){return 1000000000;} if(abs(length2-oneco)>=2){return 1000000000;} vector<int> one; vector<int> two; for(int i=0;i<length;i++){ if(num[i]){one.push_back(numbers[i]);} else{two.push_back(numbers[i]);} } int len1 = one.size(); int len2 = two.size(); //cout << len1 << len2 << endl; // int num1[10];int num2[10]; vector<int> num1; vector<int> num2; //cout << one[1] << one[2] << endl; int count1=0;int count2 = 0; sort(one.begin(),one.end()); sort(two.begin(),two.end()); do{ int num=0; for(int i=1;i<len1;i++){ int onei = one[i]; for(int i2=0;i2<i;i2++){ onei = onei*10; } num = num + onei; }//cout << num << endl; if(one[0]==0){num = num;} else {num = num + one[0];} num1.push_back(num); //cout << num << endl; count1++; }while(next_permutation(one.begin(),one.end())); do{ int num = 0; for(int i=1;i<len2;i++){ int twoi = two[i]; for(int i2 =0;i2<i;i2++){ twoi = twoi*10; } num = num + twoi; // cout << num << endl; }//cout << "here" << num << endl; if(two[0]==0){num = num;} else {//cout << num ; num = num + two[0]; //cout << " " << num << endl; } num2.push_back(num); //cout << "here" << num << endl; count2++; }while(next_permutation(two.begin(),two.end())); int ans = 1000000000; //cout << len2; int dummy1 = 1; for(int x=1;x<len1;x++){ dummy1 = dummy1*10; }//cout << dummy1; int dummy2 = 1; for(int x=1;x<len2;x++){//cout << dummy2<< endl; dummy2 = (dummy2)*10; //cout << dummy2<< endl; }//cout << dummy2; for(int i=0;i<count1;i++){//cout << num1[i] << dummy1 << endl; if((num1[i]%dummy1)==num1[i]){if(num1[i]!=0){continue;}} for(int i2=0;i2<count2;i2++){ if((num2[i2]%dummy2)==num2[i2]){if(num1[i]!=0){continue;}} ans = min(ans,abs(num1[i]-num2[i2])); } } return ans; } //int permutation(int i[10]){return 1;} int dfs(int i,int num[10]){ if(i==length) return permutation(num); num[i]=0; int ans1 = dfs(i+1,num); num[i]=1; int ans2 = dfs(i+1,num); return min(ans1,ans2); } int main(){ cin >> n; getchar(); for(int i=0;i<n;i++){ /*for(length=0;length<10;length++){ cin >> numbers[length]; char c = getchar(); if(c=='\n'){break;} }*/ string str; while(1){ char c = getchar(); if(c=='\n'){break;} str += c;} length = 0; for(int i2=0;i2<str.length();i2=i2+2){ numbers[length] = (int)str[i2]-'0'; length++; } // cout << length; int dummy[10] = {0,0,0,0,0,0,0,0,0,0}; cout << dfs(1,dummy) << endl; } } 上記のどこが間違っているか教えてください。POJの2718です。書いてあるテストは通りました。

  • しりとり 無限ループ?

    【予約語から最長のしりとりを作ろう!】 https://codeiq.jp/ace/stakemura/q408 この問題やってるんですが 処理がtimeoutしちゃいます 最長の結果が10個程度の時は期待通りに動作します 期待される結果が20程度になると(?)timeoutします 単にウチのマシンじゃムリなのか、工夫が足りないのか 無限ループを起こしてるのか、重いだけなのか判断つきません よろしくお願いします (cpp11_keywords.csvはC++の予約語84個のcsvです) <?php $data=explode(chr(10),file_get_contents('cpp11_keywords.csv')); foreach($data as $i=>$cpp){$data[$i]=trim($data[$i]);} echo(implode('<br/>',createSiritori($data))); function createSiritori($words){ $rtn=array(); $data=array(); for($i=0,$len=count($words);$i<$len;$i++){ $data[$i]=array(); for($j=0;$j<$len;$j++){ if($i==$j)continue; if(is_connectable($words[$i],$words[$j]))$data[$i][]=$j; } } $rcd=0; for($i=0;$i<$len;$i++){ $crr=array($i); for($j_arr=array(0),$j_ind=0,$len_arr=array(count($data[$i]));$j_arr[0]<$len_arr[0];$j_arr[$j_ind]++){ if($j_arr[$j_ind]>=$len_arr[$j_ind]){ array_pop($crr); array_pop($j_arr); array_pop($len_arr); $j_ind--; }else if(!in_array($data[end($crr)][$j_arr[$j_ind]],$crr)){ $crr[]=$data[end($crr)][$j_arr[$j_ind]]; $j_ind++; $j_arr[$j_ind]=0; $len_arr[$j_ind]=count($data[end($crr)]); if($j_ind>$rcd){$rcd=$j_ind;$rtn=$crr;} } } } for($i=0,$len=count($rtn);$i<$len;$i++){ $rtn[$i]=$words[$rtn[$i]]; } return $rtn; } function is_connectable($a,$b){ return (substr($a,-1)==substr($b,0,1)); }

    • ベストアンサー
    • PHP
  • Double.parseDoubleの使い方

    Java初心者です。 以下のブログラムをコマンドライン引数が実数の場合に処理できるよう にしたいのですが、うまくいきません。どうしたらいいでしょうか? 申し訳ありませんが、ご回答、よろしくお願いいたします。 public class Narabikae { public static void main(String[] args) { int i = 0, j = 0, k = 0; double[] num = new int[args.length]; for(i = 0; i < args.length; i++) { double num[i] = Double.parseDouble(args[i]); } if (0 < args.length) { for(j = 0; j < args.length-1; j++) { for(i = j + 1; i < args.length; i++ ) { if(num[j] > num[i]) { k = num[j]; num[j] = num[i]; num[i] = k; } } } for(i = 0; i < args.length; i++) { System.out.print(num[i]); if (i != args.length-1) { System.out.print(" ⇒ "); } } } else { System.out.println("並び替えできません。"); } } }

    • ベストアンサー
    • Java
  • テキストフィールドでの全角チェックについて

    テキストフィールド内にて、全角文字以外が入力されたらエラーをだすようにしています。そのとき以下のソースだと改行した時に、enterが半角とみなされてしまう現象が起こってしまいました。 function jstrlen(str) { len = 0; for (i = 0; i < str.length; i++) { wrk = escape(str.substr(i,1)); if ((wrk.substr(0,2) == "%u") && (wrk < "%uFF71")) { len++; } len++; } return len; } function isZen(str) { len1 = jstrlen(str.value); len2 = str.value.length * 2; if(len1 != len2){ alert("半角文字が混在"); str.focus() ; }else{ alert("全角文字のみ"); } } 対処方法をどなたかよろしくお願いします。

  • 電卓のJavaScriptで

    大学でプログラミング基礎の講義を取っているのですが、そこで配られたテキストをなぜそうなるのか理解できなかったのでご教授お願いします。 電卓のJavaScriptなのですが、 <script language = "JavaScript"> count = 0; sum = 0; num = 0; flag = 0; list = new Array( "0", "0", "0", "0", "0" ); これはグローバル変数ですべてのfunctionに適応させるためのものだと 思うのですが、sum = 0;num = 0;というのはこのJavaScriptでどのような 意味を持ったものなのでしょうか? function clist( ) { for( i = 0 ; i < 5 ; i++ ) { list[ i ] = 0; } } このlist[ i ] = 0;というのは配列変数を使っているのですが、何を意味しているのでしょうか? また、このループを使うことによってどのような意味があるのでしょうか? function aclear( ) { count = 0; sum = 0; num = 0; flag = 0; clist( ); display.value = 0; } function calc1( ) { num = sum; clist( ); display.value = num; flag = 1; } function calc2( ) { num = sum; clist( ); display.value = num; flag = 2; } function calc3( ) { num = sum; clist( ); display.value = num; flag = 3; } function calc4( ) { num = sum; clist( ); display.value = num; flag = 4; } これらのcalc1からcalc4のなかの式の意味がよくわかりません(>_<) function equal( ) { if(flag == 1) { sum = num + sum; } else if(flag == 2) { sum = num - sum; } else if(flag == 3) { sum = num * sum; } else if(flag == 4) { sum = num / sum; } else { aclear( ); } display.value = sum; } function push1( ) { list[count] = 1; sum = list[count]; ↑ この部分は何を意味しているのでしょうか? for( i = 0 ; i < count ; i++ ) { temp = 1; for( j = i ; j < count ; j++) { temp = temp * 10; } sum += list[i] * temp; } count += 1; display.value = sum; } list[count] = 1; 以下同様に function push9 まで続く。 ちょっと長すぎるので、全部書きたかったのですが、無理でした。 正直さっぱりなので、困っています。

  • 二次配列のqsort

    二次配列のqsortについて分かる方に教えて頂きたいのですが 一段落のプログラムを載らせていただきました.count3[j][i]をバブルソートで降順でやってみましたが高速が要求されるため,qsortを使ってやり直したいのですが (ちなみにcount1[j][i],count2[j][i]は前で定義してあります.count4[j][i]にはiの順番を記憶するための二次配列です)  ぜひともよろしくおねがいします. int ind_near_search(int j,int t) { int i,var_num,count3[IND][VAR],count4[IND][VAR],temp1,temp2,num=0,m=0; for(i=0;i<VAR;i++){ if(individual[j].x[i]==1){ //変数が1と0の場合分け count2[j][i]=t-count[j][i]; }else{ count2[j][i]=count[j][i]; } if(individual[j].x[i]==1){ //全てcount3に値を入れる count3[j][i]=count2[j][i]; }else{ count3[j][i]=count[j][i]; } } for(i=0;i<VAR;i++){ count4[j][i]=num++; } for(m=0;m<VAR-1;m++){ for(i=0;i<VAR;i++){ //バブルソートにより降順に並べ換え if(count3[j][i]<count3[j][i+1]){ temp1=count3[j][i]; count3[j][i]=count3[j][i+1]; count3[j][i+1]=temp1; temp2=count4[j][i]; //count4にはcount3の並べ替え後の対応する番号を入れる count4[j][i]=count4[j][i+1]; count4[j][i+1]=temp2; } } } for(i=0;i<VAR;i++){ var_num=count4[j][i]; //count4の大きい順番からその番号をvar_numに渡す if(individual[j].x[var_num]==0){//0と1の場合分け individual[j].x[var_num]=1; }else{ individual[j].x[var_num]=0; }

  • 正規表現 誤入力にもマッチ

    単語検索のスクリプトで利用者がミスタイプしたときにもマッチするようにしたいと考えています。 例えば、1文字間違って入力した場合にもマッチするように以下のようなスクリプトを書いたのですが、もっと簡単な記述が(標準以外のモジュールを使わずに)できないでしょうか?ご教示いただけましたら嬉しいです。 以下のスクリプトでしていること・・・ hello を .ello|h.llo|he.lo|hel.o|hell. に変換してマッチ。 use strict; my $data = "hallo"; my $query = "hello"; my $q_len = length $query; my $query1 = $query; my @queries; for (my $i=0;$i<$q_len;$i++){ substr($query1, $i,1,"."); push @queries, $query1; $query1=$query; } my $regex = join ("|", @queries); if ($data=~/$regex/){ print "matched\n"; }else{ print "no match\n"; }

    • ベストアンサー
    • Perl
  • コマンドライン引数で正規表現を指定したい

    Perlでgrep -Aのようなことがしたいです。 ---------------grep.pl------------------------------- use strict; use warnings; #コマンドライン引数の確認 if(@ARGV != 3){ die "USAGE: \0 [num] [regex] [file]"; } #数字の読み込み my $num = $ARGV[0]; #正規表現の読み込み my $regex = qr/$ARGV[1]/; #ファイル名の読み込み my $file = $ARGV[2]; #該当行を保存する配列 my @lines = (); open my $fh, '<', "$file" or die "$!"; my @file = <$fh>; close $fh; for(my $i=0; $i<@file; $i++){ if($file[$i] =~ /$regex/){ push @lines, $file[$i]; for(my $j=1; $j<=$num; $j++){ if($i+$j < @file){ if($file[$i+$j] !~ /$regex/){ push @lines, $file[$i+$j]; }else{ last; } }else{ last; } } } } foreach my $item (@lines){ print $item; } ------------------------------------------------- ところが、正規表現がうまく読み込めません。 perl grep.pl 2 \d{4}\/\d{2}\d{2} test.txt などとしても、\d{4}\/\d{2}\d{2}の部分が機能しません。 コマンドライン引数から正規表現を指定するにはどうしたらよいでしょうか。

    • ベストアンサー
    • Perl
  • 電卓のJavaScript

    初心者で申し訳ないのですが、電卓のソースを作ってみたのですが、JavaScriptが間違っているためか「ページにエラーが発生しました」となり計算が行われません。 どのように、改変すればいいのでしょうか?どうかご教授お願いします。 <html> <head> <title> 電卓 </title> <script language = "JavaScript"> count = 0; sum= 0; flag =0; list = new Array( "0", "0","0","0","0",); function clist( ) { for( i = 0 ; i < 5 ; i++ ) { list[i] =0; } } function calc1() { num = sum; clist( ); display.value = num; flag = 1; } function calc2() { num = sum; clist( ); display.value = num; flag = 2; } function calc3() { num = sum; clist( ); display.value = num; flag = 3; } function calc4() { num = sum; clist( ); display.value = num; flag = 4; } function calc5() { clist( ); } function equal() { if(flag==1) { sum=num+sum; display.value=sum; clist( ); } else if(flag==2) { sum=num-sum; display.value=sum; clist( ); } else if(flag==3) { sum=num*sum; display.value=sum; clist( ); } else if(flag==4) { sum=num/sum; display.value=sum; clist( ); } } function push0( ) { list[count] = 0; sum = list[count]; for( i = 0 ; i < count ; i++ ) { temp=1; for( j = i ; j < count ; j++ ) { temp=temp*10; } sum+ =list[i]*temp; } count+=1; display.value=sum; } function push1( ) { list[count] = 1; sum = list[count]; for( i = 0 ; i < count ; i++ ) { temp=1; for( j = i ; j < count ; j++ ) { temp=temp*10; } sum+ =list[i]*temp; } count+=1; display.value=sum; } 同様に2~9 </script> </head> <body> <hr><br> <input type = "button" value ="7" onclick = "push7()">&nbsp <input type = "button" value ="8" onclick = "push8()">&nbsp <input type = "button" value ="9" onclick = "push9()">&nbsp&nbsp <input type = "button" value ="+" onclick = "calc1()">&nbsp<br><br> <input type = "button" value ="4" onclick = "push4()">&nbsp <input type = "button" value ="5" onclick = "push5()">&nbsp <input type = "button" value ="6" onclick = "push6()">&nbsp&nbsp <input type = "button" value ="-" onclick = "calc2()">&nbsp<br><br> <input type = "button" value ="1" onclick = "push1()">&nbsp <input type = "button" value ="2" onclick = "push2()">&nbsp <input type = "button" value ="3" onclick = "push3()">&nbsp&nbsp <input type = "button" value ="×" onclick = "calc3()">&nbsp<br><br> <input type = "button" value ="0" onclick = "push0()">&nbsp <input type = "button" value ="=" onclick = "equal()">&nbsp <input type = "button" value ="C" onclick = "calc5()">&nbsp&nbsp <input type = "button" value ="÷" onclick = "calc4()">&nbsp<br><br> <br><br><hr><br>&nbsp&nbsp&nbsp <input type = "text" size ="10" name = "display">&nbsp <br><br><hr><br> </body> </html>

  • 最頻度のプログラム

    以下のような最頻度のプログラムを作成しました.最頻度が1つしか存在しないような場合はうまく動くと思います.しかし最頻度の数字が2つ以上存在すると,一番はじめに書い最頻度の数字しか表示しないと思います.どう改良すれば,すべての最頻度の数字を拾ってくれますかね. /*最頻値を求めるプログラム*/ #include<stdio.h> int main(void) { int i,j; int count=0,COUNT=0; double num[20]; double max; printf("最頻値を求めます.数字を20個入力してください.\n"); for(i=0;i<20;i++) { printf("%d\t",i+1); scanf("%lf",&num[i]); } for(i=0;i<20;i++) { count=0; for(j=i+1;j<20;j++) { if(num[i]==num[j]) { count++; } if(COUNT<count-1) { COUNT=count; max=num[i]; } } } printf("%lfが最頻値です.\n",max); return 0; }