• ベストアンサー

プログラムを再帰的に実行させたい

いつもお世話になっています。 ブログのトラックバック先のURLを取得するプログラムを作成しているのですが、 以下のようなプログラムを例において、 プログラムを再帰的に実行させたいです。 public class BlogTB { public static void main(String[]args){ String url1 = args[0]; String[] TBURL =HTMLTB.getHTMLtb(url1); for(int i=0;i<TBURL.length;i++){ System.out.println(TBURL[i]); } } HTMLTB.getHTMLtbでは、以前の質問の http://oshiete1.goo.ne.jp/kotaeru.php3?q=1725502 ご回答を参考にして作成した各ブログサービスごとに対応する トラックバック先のURLを取得する処理を行い、 HTMLをパースしてトラックバック先のURLを抽出し、 その一覧をTBURLに格納します。 例えば、ブログAの記事に、 B,C,D,E,Fのブログがトラックバックをしていたとすると、 上記のプログラムの結果として、ブログAのURLを入力すると、 B,C,D,E,FのブログのURLを表示するようになっています。 そこで、ブログAにトラックバックをしていたブログBにa,b,cのブログがトラックバックしていて、 同様にブログEにはd,eのブログがトラックバックをしていて、 さらにブログcにはブログ1,2がトラックバックをしていたとします。 このとき、B,C,D,E,FのブログのURLだけでなく、 a,b,cとd,eと1,2のブログのURLも取得したいと思っています。 つまり、プログラムを再帰的に動かして、 ブログAからたどれる全てのブログのURLを取得したいと思っています。 そのようにするには、上記のプログラムの中で、 どのような処理をさせればいいでしょうか? よろしくお願いします。

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

  • ベストアンサー
  • osumitan
  • ベストアンサー率33% (102/307)
回答No.1

さーっと書いてみましたが、どうでしょうか? (テストしてないので動かないかもしれませんが) addUrlを再帰的に呼び出すようにしてますが、 トラックバックの階層については意識しないで 見つかったものからひたすらArrayListにつっこんでます。 ---------------- import java.util.ArrayList; public class BlogTB {   public static void main(String[] args) {     ArrayList al = new ArrayList();     String url = args[0];     addUrl(al, url);     String[] TBURL = (String[])al.toArray(new String[0]);     for(int i = 0 ; i < TBURL.length ; i++) {       System.out.println(TBURL[i]);     }   }   private static addUrl(ArrayList al, String url) {     al.add(url);     String[] TBURL = HTMLTB.getHTMLtb(url);     for(int i = 0 ; i < TBURL.length ; i++) {       addUrl(al, TBURL[i]);     }   } }

shows
質問者

お礼

ご回答ありがとうございました。 とりあえず、上記のプログラムを試してみたのですが、 以下のようなエラーがでました。 BlogTB.java:19: メソッドの宣言が不正です。戻り値の型が必要です。 private static addUrl(ArrayList al, String url) { ^ BlogTB.java:13: シンボルを解釈処理できません。 シンボル: メソッド addUrl (java.util.ArrayList,java.lang.String) 位置 : BlogTB の クラス addUrl(al, url); ^ BlogTB.java:23: シンボルを解釈処理できません。 シンボル: メソッド addUrl (java.util.ArrayList,java.lang.String) 位置 : BlogTB の クラス addUrl(al, TBURL[i]); この場合戻り値の型として何を指定すればよいでしょうか? また、色々戻り値の型を試したのですが、 return 文が指定されていないというエラーが出ます。 returnには何を指定すればよいのでしょうか? よろしくお願いします。

その他の回答 (4)

  • bobviv
  • ベストアンサー率50% (13/26)
回答No.5

 addUrlメソッドのforループの直前に、   if (TBURL[0].equals("")) return; を入れてみてはいかがでしょう?  参照されている以前の質問で回答されているGetTBAddrYAHOO#getTBaddrYAHOO(String)のソースを見るかぎり、このメソッドの戻り値配列は、初期値が""のStringをもとにString#split(String)で生成されているようなので、該当するurlが一個も見つからなかった場合でも、長さが1で、先頭に""を格納した配列が返されてしまい、処理すべきものがなくなってもforループが回り続けているのではないでしょうか。  HTMLTB.getHTMLtb(String)のソースが無いので正確かどうかは分かりませんが。。。      

shows
質問者

お礼

ご回答ありがとうございます。 ご指摘のようにプログラムを改正したら無事動くようになりました。 分かりやすい説明ありがとうございました。

  • osumitan
  • ベストアンサー率33% (102/307)
回答No.4

> 再帰プログラムのよくある罠「終点設定がない」のだと思います。 確かにその通りでしたね…。 重複するURLを登録しない仕組みが必要でしょうね。 > An unexpected exception has been detected in native code outside the VM. > Unexpected Signal : EXCEPTION_STACK_OVERFLOW occurred at PC=0x7C941202 > Function=RtlDeactivateActivationContextUnsafeFast+0x8 > Library=C:\WINDOWS\system32\ntdll.dll > よって、終点設定をしていないプログラムでもループになることは無いはずなのですが、 > エラーが起きてしまいました。 しかし、終点がないために起こるスタックオーバーフローであれば、 java.lang.StackOverflowErrorが発生することになるはずなんですが… もしHTMLTB.getHTMLtbの中でnativeなライブラリを呼んでいるようなら その中でエラーが起こっていたりするのではないですか? (ある特定の条件を持った記事でのみ発生する現象であるとか)

shows
質問者

お礼

ご回答ありがとうございます。 とりあえず、No2のお礼にて書いた問題は解決しました。 ところで、ご回答のなかにもありますように、 トラックバック返しやループに陥る時など、 重複するURLを登録しないようにするにはどのようにすればよいでしょうか?

  • hrm_mmm
  • ベストアンサー率63% (292/459)
回答No.3

再帰プログラムのよくある罠「終点設定がない」のだと思います。 出発サイトurl内のリンクから、次のサイトのurl内リンクをチェックするところまではよいけど、 その次にまた元サイトurlが出てきたのに、既に読んだかどうかチェックしてないから、 読まずに食べた白山羊黒山羊メールと同じことになって、無限ループしてるのではないでしょうか? 登録しようとしているurlがalに既に登録済みかどうかのチェック機構を付けて、登録済みならなにもせず処理終了にすれば、うまくいくと思います。

shows
質問者

お礼

ご回答ありがとうございます。 確かに今回のプログラムでは、「終点設定」がなく、 ループになる場合を考慮していないので、 将来的にはその方法を考えなくてはならないと思っています。 ただ、今回No2様のお礼にて、 例として実行した場合は、 http://blogs.yahoo.co.jp/nyohohooon/3163543.html の記事に対して実行したのですが、 この場合はループにならないケースを選びました。 このヤフーのブログには、あるヤフーのブログAがトラックバックされていて、 ブログAにはヤフーのブログB(正確にはブログAの違う記事)がトラックバックされています。 Bのブログにはトラックバックがないので、ここが終点となります。 トラックバック返しはしていないのでループもなりません。 よって、終点設定をしていないプログラムでもループになることは無いはずなのですが、 エラーが起きてしまいました。 なぜエラーが起きるのか分からないでいます。

  • osumitan
  • ベストアンサー率33% (102/307)
回答No.2

あーごめんなさい、間違ってましたね。 「private static void addUrl」でしたね。 戻り値は特にないので「void」です。 (コンパイルさえ試していなかったもので。。。。)

shows
質問者

お礼

度々すみません。 プログラムを修正して実行したのですが、 実行時にaddUrl(al, TBURL[i]);でエラーが起きるというか、 無限ループになってしまいます。 HTMLTB.getHTMLtbはスペース上書けないので、 以前の質問 http://oshiete1.goo.ne.jp/kotaeru.php3?q=1725502 のGetTBAddrYAHOOを使ったプログラムで説明します。 public class BlogTBYAHOO { public static void main(String[] args) { ArrayList al = new ArrayList(); String url = args[0]; addUrl(al, url); String[] TBURL = (String[])al.toArray(new String[0]); for(int i = 0 ; i < TBURL.length ; i++) { System.out.println(TBURL[i]); } } private static void addUrl(ArrayList al, String url) { al.add(url); String[] TBURL =GetTBAddrYAHOO.getTBaddrYAHOO(url); for(int i = 0 ; i < TBURL.length ; i++) { addUrl(al, TBURL[i]); } } } このプログラムを http://blogs.yahoo.co.jp/nyohohooon/3163543.html の記事に対して実行してみました。 このヤフーのブログには、あるヤフーのブログAがトラックバックされていて、 ブログAにはヤフーのブログBがトラックバックされています。 上記のプログラムを実行すると、A,B,CのURLが取得されるはずなのですが、 無限ループになります。 同様のことがプログラムBlogTBでも起こっていると思います。 解決方法をお願いします。

shows
質問者

補足

BlogTBに関するエラーは以下のようになります。 An unexpected exception has been detected in native code outside the VM. Unexpected Signal : EXCEPTION_STACK_OVERFLOW occurred at PC=0x7C941202 Function=RtlDeactivateActivationContextUnsafeFast+0x8 Library=C:\WINDOWS\system32\ntdll.dll Current Java thread: at java.util.regex.Pattern.compile(Pattern.java:1254) at java.util.regex.Pattern.<init>(Pattern.java:1013) at java.util.regex.Pattern.compile(Pattern.java:760) at java.util.regex.Pattern.matches(Pattern.java:846) at java.lang.String.matches(String.java:1634) at HTMLTB3.getHTMLtb3(HTMLTB3.java:53) at BlogTB.addUrl(BlogTB.java:21) at BlogTB.addUrl(BlogTB.java:23) at BlogTB.addUrl(BlogTB.java:23) at BlogTB.addUrl(BlogTB.java:23)             ・             ・             ・