1

さて、私はJavaのトレーディングカードゲームに基づいたゲームに取り組んでいます。すべてのゲームピースの「情報」をcsvファイルにスクレイプしました。各行はゲームピースであり、各列はそのピースの属性のタイプです。バッファリーダーなどでコードを書くのに何時間も費やして、csvファイルから2D配列に情報を抽出しようとしましたが、役に立ちませんでした。私のcsvファイルはここにリンクされています:http://dl.dropbox.com/u/3625527/MonstersFinal.csv私は1年間コンピュータサイエンスを学んでいますが、それでもこれを行う方法がわかりません。

だから私の主な質問は、行と列を維持できるようにこれを2D配列に配置するにはどうすればよいですか?

4

3 に答える 3

1

さて、前に述べたように、あなたの文字列のいくつかはコンマを含んでいるので、最初は悪い場所から始めていますが、私には解決策があります、そしてそれはこれです:

  1. ---------可能であれば、サイトを再スクレイプしますが、そうする場合は単純なエンコード操作を実行します。HTMLを含む自動生成されたXMLファイルで行われる傾向があることに気付くようなことをしたいと思うでしょう。'制御文字'(ここでは、デバッグと...まあ...正気のために印刷可能な文字が最適です)を予約します。これは、一度エンコードされると、それ自体のインスタンスとして直接読み取られることを意図したものではありません。アンパサンドは私が使用するのが好きなものです。それは十分に珍しいですが、それでも印刷可能ですが、実際に使用したい文字はあなた次第です。私がすることは、「、」のすべてのインスタンスで、CSVに書き込まれる前にそのコンマが「&c」に置き換えられ、サイト上の実際のアンパサンドのすべてのインスタンスで、「&c」になるようにプログラムを作成することです。 「」は「&a」に置き換えられます。

  2. --------各行にいくつの列があるかがわかっていると仮定すると、StringTokenizerクラスを使用できます(調べてみてください。すばらしいもので、Javaに組み込まれています。情報を探すのに適した場所は、いつものように、 Javaチュートリアル)を使用して、必要な値を配列の形式で自動的に提供します。

    • 文字列と区切り文字(この場合、区切り文字は'、')を渡すことで機能し、これらのコンマで区切られたすべてのサブ文字列を吐き出します。最初から合計でいくつのピースがあるかがわかっている場合は、最初に2D配列をインスタンス化して、StringTokenizerから提供される各行をプラグインするだけです。そうでない場合でも、ArrayListを使用できるため、問題ありません。ArrayListは、配列の高レベルの抽象化であり、追加を継続して取得時間が常に一定になることを認識できるように、より多くのメモリを自動的に要求するため、優れています。ただし、ピースを動的に追加することを計画していて、それらを取得するよりも頻繁に行う場合は、取得時間が線形であるため、代わりにLinkedListを使用することをお勧めします。ただし、追加と削除の時間については、ArrayListよりもはるかに優れた関係です。または、あなたが素晴らしいなら、代わりにスキップリストを使うことができます。それらがデフォルトでJavaに実装されているかどうかはわかりませんが、すばらしいです。ただし、公正な警告。取得、削除、および配置の速度のコストは、メモリの面でオーバーヘッドが増加します。スキップリストは多くのポインタを維持します。

    • 各行に同じ数の値が必要であり、それらを位置的に整理する必要があることがわかっているが、何らかの理由でスクレーパーが行の値の不足を処理せず、それを配置しない場合値、いくつかの悪いニュースがあります...さまざまな長さの配列を解釈し、それぞれのPieceオブジェクトをインスタンス化するメソッドを作成するよりも、値の不足を処理するスクレーパーコードの部分を書き直す方が簡単です。配列。これについての私の提案は、後で解釈するために、制御文字を使用し、空の列に&n('null'の場合)を入力することですが、もちろん、詳細はコードとコーディングスタイルを個別化するものなので、私が言うことではありません。

編集:あなたが焦点を当てるべき主なことは、Javaで利用可能なさまざまな標準ライブラリのデータ型を学ぶことであり、おそらくそれらのいくつかを練習のために自分で実装することを学ぶことだと思います。二分探索木を実装したことを覚えています。AVLツリーではありませんが、問題ありません。それは十分に楽しく、優れたコーディングプラクティスであり、さらに重要なことに、物事を迅速かつ効率的に実行できるようにするために必要です。定義は「メモリの連続セクション」であるため、Javaが配列を実装する方法は正確にはわかりませんが、実行時に変数を使用してJavaで配列にメモリを割り当てることができます...ただし、特定のJava実装に関係なく、配列は多くの場合そうではありません最善の解決策ではありません。また、正規表現を知っていると、すべてが大いに役立ちますより簡単に。練習のために、それらをJavaプログラムに組み込むことをお勧めします。または、毎回コンパイルしてjarを作成する必要がない場合は、bashスクリプト(* nixを使用している場合)および/またはバッチスクリプト( 'Windowsを使用しています)。

于 2012-06-22T00:34:42.957 に答える
1

データをスクレイピングした方法によって、この問題は必要以上に難しくなっていると思います。ほとんどの値が一貫性のない引用符で囲まれ、一部のデータにはすでにコンマが含まれており、各カードが独自の行にあるわけではないことを考えると、スクレイプは一貫性がなく、操作が難しいようです。

次のような、より一貫性のある形式でデータを再スクレイピングしてみてください。

R1C1|R1C2|R1C3|R1C4|R1C5|R1C6|R1C7|R1C8
R2C1|R2C2|R2C3|R2C4|R2C5|R2C6|R2C7|R3C8
R3C1|R3C2|R3C3|R3C4|R3C5|R3C6|R3C7|R3C8
R4C1|R4C2|R4C3|R4C4|R4C5|R4C6|R4C7|R4C8
A/D Changer|DREV-EN005|Effect Monster|Light|Warrior|100|100|You can remove from play this card in your Graveyard to select 1 monster on the field. Change its battle position.

各行が間違いなく独自のカードであり(奇数の場所に新しい行を付けて投稿したCSVの例とは対照的に)、区切り文字が区切り文字以外のものとしてデータフィールドで使用されることはありません。

入力を一貫して読み取り可能な状態にすると、解析が非常に簡単になります。

    BufferedReader br = new BufferedReader(new FileReader(new File("MonstersFinal.csv")));
    String line = "";

    ArrayList<String[]> cardList = new ArrayList<String[]>(); // Use an arraylist because we might not know how many cards we need to parse.

    while((line = br.readLine()) != null) { // Read a single line from the file until there are no more lines to read
        StringTokenizer st = new StringTokenizer(line, "|"); // "|" is the delimiter of our input file.
        String[] card = new String[8]; // Each card has 8 fields, so we need room for the 8 tokens.
        for(int i = 0; i < 8; i++) { // For each token in the line that we've read:
            String value = st.nextToken(); // Read the token
            card[i] = value; // Place the token into the ith "column"
        }
        cardList.add(card); // Add the card's info to the list of cards.
    }

    for(int i = 0; i < cardList.size(); i++) {
        for(int x = 0; x < cardList.get(i).length; x++) {
            System.out.printf("card[%d][%d]: ", i, x);
            System.out.println(cardList.get(i)[x]);
        }
    }

これにより、指定した入力例に対して次の出力が生成されます。

card[0][0]: R1C1
card[0][1]: R1C2
card[0][2]: R1C3
card[0][3]: R1C4
card[0][4]: R1C5
card[0][5]: R1C6
card[0][6]: R1C7
card[0][7]: R1C8
card[1][0]: R2C1
card[1][1]: R2C2
card[1][2]: R2C3
card[1][3]: R2C4
card[1][4]: R2C5
card[1][5]: R2C6
card[1][6]: R2C7
card[1][7]: R3C8
card[2][0]: R3C1
card[2][1]: R3C2
card[2][2]: R3C3
card[2][3]: R3C4
card[2][4]: R3C5
card[2][5]: R3C6
card[2][6]: R3C7
card[2][7]: R4C8
card[3][0]: R4C1
card[3][1]: R4C2
card[3][2]: R4C3
card[3][3]: R4C4
card[3][4]: R4C5
card[3][5]: R4C6
card[3][6]: R4C7
card[3][7]: R4C8
card[4][0]: A/D Changer
card[4][1]: DREV-EN005
card[4][2]: Effect Monster
card[4][3]: Light
card[4][4]: Warrior
card[4][5]: 100
card[4][6]: 100
card[4][7]: You can remove from play this card in your Graveyard to select 1 monster on the field. Change its battle position.

情報を再スクレイピングすることがここでのオプションであり、何も誤解していないことを願っています。幸運を!

最後に、問題が解決したら、OOPを利用することを忘れないでください。クラスを使用するCardと、データの操作がさらに簡単になります。

于 2012-06-22T03:50:15.863 に答える
0

私は機械学習で使用するために同様の問題に取り組んでいるので、このトピックで私ができることを共有しましょう。

1)行の解析を開始する前に、プログラムにハードコードされているかどうか、またはこの情報を提供するヘッダーがファイルにあるかどうか(強く推奨)がわかっている場合は、行ごとにいくつの属性がありますか?たとえば、最初の属性はRowString.substring(0、RowString.indexOf('、'))になり、2番目の属性は最初のコンマから次のコンマまでの部分文字列になります(関数の記述)。コンマのn番目のインスタンスを見つける、または文字列を通過するときに文字列のビットを切り取るのはかなり簡単なはずです)、最後の属性はRowString.substring(RowString.lastIndexOf('、')、RowStringになります。長さ())。Stringクラスのメソッドはここであなたの友達です。

2)値を区切ることを目的としたコンマと、文字列形式の属性の一部であるコンマを区別するのに問題がある場合は、(ファイルが手動で再フォーマットできるほど小さい場合)Javaが行うことを実行します-文字を次のように表します'、'だけでなく、'\、'を含む文字列内にある特別な意味。そうすれば、「\」ではなく「、」のインデックスを検索できるので、文字を区別する方法があります。

3)2)の代わりに、CSV(私の意見では)は、コンマを含むことが多い文字列には適していません。CSVには実際の一般的な形式はないので、コロンで区切られた値、ダッシュで区切られた値、さらにはトリプルアンパサンドで区切られた値にしないのはなぜですか。値をコンマで区切ることのポイントは、値を簡単に区別できるようにすることです。コンマが機能しない場合は、値を保持する理由はありません。繰り返しますが、これはファイルが手作業で編集できるほど小さい場合にのみ適用されます。

4)ファイルをフォーマットだけでなく見ると、手作業ではできないことが明らかになります。さらに、一部の文字列は三重二重引用符( "" "string" "")で囲まれ、一部の文字列は単一二重引用符( "string")で囲まれているように見えます。推測しなければならない場合、引用符に含まれるものはすべて単一の属性であると言えます。たとえば、ある属性で始まり、別の属性で終わる引用符のペアはありません。したがって、次のことができると言えます。文字列をコンマで区切られた各フィールドに分割するメソッドを使用してクラスを作成します。奇数の二重引用符が前に付いたコンマを無視するようにそのメソッドを記述します(このように、引用符のペアが閉じられていない場合、それが文字列内にあり、コンマが値の区切り文字ではないことがわかります)。この戦略、

于 2012-06-21T23:52:15.670 に答える