2

さまざまな種類の区切り文字 (チルダ、スペース、コンマ、パイプ、キャレット文字) を持つテキスト ファイルを解析する必要があります。

区切り文字が何であるかに応じて、要素の順序も異なります。次に例を示します。

comma: A, B, C, D, E
caret: B, C, A, E, D
tilde: C, A, B, D, E 

区切り文字はファイル内では同じですが、ファイルごとに異なります。私が知る限り、データ要素内に区切り文字はありません。

普通の Java でこれを行うための良いアプローチは何ですか?

4

10 に答える 10

3

ファイルの最初の 2 行を読み取り、区切り文字をテストするのが好きです。区切り文字で分割し、両方の行がゼロ以外の同じ数のピースを返す場合、おそらく正しいものを推測しています。以下は、names.txt ファイルをチェックするプログラムの例です。

public static void main(String[] args) throws IOException {
    File file = new File("etc/names.txt");

    String delim = getDelimiter(file);
    System.out.println("Delim is " + delim + " (" + (int) delim.charAt(0) + ")");
}

private static final String[] DELIMS = new String[] { "\t", ",", " " };

private static String getDelimiter(File file) throws IOException {
    for (String delim : DELIMS) {

        BufferedReader br = new BufferedReader(new FileReader(file));
        String[] line0 = br.readLine().split(delim);
        String[] line1 = br.readLine().split(delim);
        br.close();
        if (line0.length == line1.length && line0.length > 1) {
            return delim;
        }
    }
    throw new IllegalStateException("Failed to find delimiter for file " + file);
}
于 2009-11-12T05:09:33.530 に答える
2

私はJavaのStringTokenizerで遊ぶことから始めるかもしれません。これは文字列を取り、区切り文字で区切られた各トークンを見つけることができます。

これがネットからの一例です。

しかし、あなたはファイルから物事をトークン化したいのです。その場合は、ファイルストリームからの入力を解析できるJavaのStreamTokenizerを試してみることをお勧めします。

編集

区切り文字が事前にわからない場合は、いくつかのことができます。

  1. 可能なすべての区切り文字に基づいて区切ります。データ自体に区切り文字がない場合、これは機能します。(つまり、「、」と「;」の両方を探します-データ自体がこれらの文字のどちらも含まない場合)
  2. データがどのように見えるか(整数または単一文字であると想定される)がわかっている場合、コードはさまざまな区切り文字を試すことができます(最初に「、」を試し、次に「;」などを試す)。テキストの行を「正しく」解析しました。
于 2009-11-12T04:31:45.197 に答える
1

同じ区切り文字がファイル全体にある場合は、おそらくファイルをロードして解析するときに、区切り文字を入力できます。

例を言う。

    void someFunction(char delimiter){
--- do wateva you want to do with the file --- // you can use stringTokenizer for this purpose
}

ファイルをロードするたびに、引数としてファイルの区切り文字を指定してこの関数を呼び出すことにより、この関数を使用できます。

お役に立てれば.. :-)

于 2009-11-12T04:32:13.387 に答える
1

ファイル全体で同じ区切り文字である場合は、1 つの区切り文字に対して関数を作成し、それをdと呼び、他のファイルを処理するときは、それらの区切り文字をdに置き換えます。リンス。繰り返す。:)

別のアプローチ: 解析関数がファイル名と区切り文字をパラメーターとして受け入れるようにします。これは、解析ロジックがすべてのファイルで同じであることを前提としています。

ファイルが完全に異なって見える場合 - 区切り文字よりも問題が少ないです。

于 2009-11-12T04:19:54.687 に答える
1

考えられるアプローチの 1 つは、Java Compiler Compiler ( https://javacc.dev.java.net/ ) を使用することです。これにより、何を受け入れるか、どの区切り文字が一度に表示されるかについての一連のルールを作成できます。使用されている区切り文字に応じて、順序の問題を回避するルールをエンジンに与えることができます。また、ファイルは、必要に応じて途中で区切り文字を切り替えることができます。

于 2009-11-12T04:58:21.397 に答える
1

次のようなファイルを解析するクラスを作成できます。

interface MyParser {
  public MyParser(char delimiter, List<String> fields);

  Map<String,String> ParseFile(InputStream file);
}

デリミタとフィールドの順序付きリストをコンストラクタに渡し、ファイルを解析するように依頼します。(順序付けられたリストから) フィールド名から値へのマップが返されます。

ParseFile の実装では、おそらく区切り文字で分割を使用し、分割によって返された配列とフィールドのリストを同時に反復処理し、マップを作成します。

于 2009-11-12T04:35:31.003 に答える
1

前述のように StringTokenizer を使用できます。はい、考えられるすべての区切り文字に対して文字列を指定する必要があります。トークナイザーの「returnsDelims」プロパティを設定することを忘れないでください。そうすれば、ファイルで使用されているトークンがわかり、それに応じてデータを解析できます。

于 2009-11-12T05:51:04.723 に答える
1

特定の区切り文字が使用されているときにレコードの正確な順序がわかっている場合は、各行の Record オブジェクトを返すパーサーを作成するだけです...以下のようなものです。

これには多くのハードコードされた値が含まれていますが、これがどれほど柔軟に必要かはわかりません。これは、拡張できるものではなく、スクリプト/ハッキーなソリューションだと思います。区切り文字がわからない場合は、String.split() メソッドを使用してファイルの最初の行をテストし、列数が予想される数と一致するかどうかを確認できます。

 class MyParser

    {
        public static Record parseLine(String line, char delimiter)
        {
            StringTokenizer st1 = new StringTokenizer(line, delimiter);
            //You could easily use an array instead of these dumb variables
            String temp1,temp2,temp3,temp4,temp5;

            temp1 = st1.getNextToken();
            .. etc..

            Record ret = new Record();
            switch (delimiter)
            {
                case '^':
                ret.A = temp2;
                ret.B = temp3;
                ...etc...
                break;
                case '~':
                ...etc...
                break;
            }
        }
    }

    class Record
    {
        String A;
        String B;
        String C;
        String D;
        String E:
    }
于 2009-11-12T05:44:54.733 に答える
1

ファイル内の区切り文字を見つける 1 つの方法は、ある種の正規表現を使用することです。簡単なケースは、アルファベットでも数字でもない任意の文字を見つけることです: [^A-Za-z0-9]

static String getDelimiter(String str) {
  Pattern p = Pattern.compile("([^A-Za-z0-9])");
  Matcher m = p.matcher(str.trim()); //remove whitespace as first char(s)
  if(m.find())
   return m.group(0);
  else 
   return null;
 }




public static void main(String[] args) {
  String[] str = {" A, B, C, D", "A B C D", "A;B;C;D"};
  for(String s : str){   
   String[] data = s.split(getDelimiter(s));
   //do clever stuff with the array
  }
 }

この場合、ファイルから読み取るのではなく、配列からデータをロードしました。ファイルから読み取る場合は、最初の行を getDelimiter メソッドにフィードします。

于 2009-11-12T09:50:26.363 に答える
0

オープン ソースの CSV 解析ライブラリのほとんどでは、区切り文字を変更できます。また、エスケープを処理するための動作が組み込まれています。 最近はOpencsvが流行っているらしいのですが、私はまだ使ったことがありません。前回、多くの csv 解析を行わなければならなかったときは、 Ostermiller csv ライブラリにかなり満足していました。

于 2009-11-12T04:56:30.183 に答える