3

ファイルから読み取った文字列の正規表現を記述する必要があります

apple,boy,cat,"dog,cat","time\" after\"noon"

私はそれを分割する必要があります

りんご
男の子
猫
犬猫
時間"後"正午

使ってみた

Pattern pattern = 
Pattern.compile("[\\\"]");
String items[]=pattern.split(match);

第二部ですが、正しい答えが得られませんでした。これを手伝ってもらえますか?

4

3 に答える 3

3

あなたの質問は正規表現の問題というよりも構文解析の問題であるため、これが機能する別の解決策です。

public class CsvReader {

    Reader r;
    int row, col;
    boolean endOfRow;

    public CsvReader(Reader r){
        this.r = r instanceof BufferedReader ? r : new BufferedReader(r);
        this.row = -1;
        this.col = 0;
        this.endOfRow = true;
    }

    /**
     * Returns the next string in the input stream, or null when no input is left
     * @return
     * @throws IOException  
     */
    public String next() throws IOException {
        int i = r.read();
        if(i == -1)
            return null;

        if(this.endOfRow){
            this.row++;
            this.col = 0;
            this.endOfRow = false;
        } else {
            this.col++;
        }

        StringBuilder b = new StringBuilder();
outerLoop:  
        while(true){
            char c = (char) i;
            if(i == -1)
                break;
            if(c == ','){
                break;
            } else if(c == '\n'){
                endOfRow = true;
                break;
            } else if(c == '\\'){
                i = r.read();
                if(i == -1){
                    break;
                } else {
                    b.append((char)i);
                }
            } else if(c == '"'){
                while(true){
                    i = r.read();

                    if(i == -1){
                        break outerLoop;
                    }
                    c = (char)i;
                    if(c == '\\'){
                        i = r.read();
                        if(i == -1){
                            break outerLoop;
                        } else {
                            b.append((char)i);
                        }
                    } else if(c == '"'){
                        r.mark(2);
                        i = r.read();
                        if(i == '"'){
                            b.append('"');
                        } else {
                            r.reset();
                            break;
                        }
                    } else {
                        b.append(c);
                    }
                }
            } else {
                b.append(c);
            }
            i = r.read();
        }

        return b.toString().trim();
    }


    public int getColNum(){
        return col;
    }

    public int getRowNum(){
        return row;
    }

    public static void main(String[] args){

        try {
            String input = "apple,boy,cat,\"dog,cat\",\"time\\\" after\\\"noon\"\nquick\"fix\" hello, \"\"\"who's there?\"";
            System.out.println(input);
            Reader r = new StringReader(input);
            CsvReader csv = new CsvReader(r);
            String s;
            while((s = csv.next()) != null){
                System.out.println("R" + csv.getRowNum() + "C" + csv.getColNum() + ": " + s);
            }
        } catch(IOException e){
            e.printStackTrace();
        }
    }
}

このコードを実行すると、次の出力が得られます。

R0C0: apple
R0C1: boy
R0C2: cat
R0C3: dog,cat
R0C4: time" after"noon
R1C0: quickfix hello
R1C1: "who's there?

これはあなたのニーズにかなりよく合うはずです。

ただし、いくつかの免責事項:

  • 値の途中にあるエスケープされていない引用符など、CSV形式の構文のエラーは検出されません。
  • 文字変換(「\ n」を改行文字に変換するなど)は実行されません。バックスラッシュを使用すると、他のバックスラッシュを含め、次の文字が文字どおりに扱われるようになります。(追加機能が必要な場合は、簡単に変更できるはずです)
  • 一部のcsvファイルは、バックスラッシュを使用するのではなく、引用符を2倍にすることで引用符をエスケープします。このコードは、両方を検索するようになりました。

編集:csv形式を調べて、実際の標準がないことを発見しましたが、バックスラッシュではなく2倍にすることでエスケープされた引用符をキャッチするようにコードを更新しました。

編集2:修正。現在宣伝どおりに機能するはずです。また、行番号と列番号の追跡をテストするように変更しました。

于 2013-03-02T22:40:32.093 に答える
0

これについてはよくわかりませんが、試してみることができますPattern.compile("[\\\\"]");

\はエスケープ文字であり\、式でa を検出するため\\\\に使用できます。

同様のことが別の状況で私のために働いたので、それがあなたの問題も解決することを願っています.

于 2013-03-02T23:07:43.167 に答える
0

最初に: String.split() は正規表現を使用して、部分文字列ではなく区切り文字を見つけます。

編集:これが String.split() で実行できるかどうかはわかりません。コンマのみを照合しながら引用符を処理できる唯一の方法は、先読みと後読みであると思いますが、それは多くの場合に失敗します。

Edit2:正規表現で実行できると確信しています。そして、この 1 つのケースは string.split() で解決できると確信していますが、一般的な解決策は単純ではありません。

基本的に、入力としてコンマ以外のものを探しています [^,]。引用符を別の文字として処理できます。私は自分自身でほとんどの道を歩んできました。私はこれを出力として取得しています:

apple

boy

cat


dog

cat



time\" after\"noon

しかし、なぜこんなに多くの空白行があるのか​​ わかりません。

私の完全なコードは次のとおりです。

String input = "apple,boy,cat,\"dog,cat\",\"time\\\" after\\\"noon\"";

Pattern pattern =
        Pattern.compile("(\\s|[^,\"\\\\]|(\\\\.)||(\".*\"))*");
Matcher m = pattern.matcher(input);

while(m.find()){
    System.out.println(m.group());
}

しかし、ええ、私は上記の人にエコーし、正規表現を使用する必要がない場合は、おそらく手動で行う方が簡単だと言います.

しかし、私はほとんどそこにいると思います。吐き出しています...ああ、ここで何が起こっているのかわかりました。私はそれを修正できると思います。

しかし、私は上記の人をエコーし​​、正規表現を使用する必要がない場合は、一度に 1 文字ずつ実行し、ロジックを手動で実装する方がおそらく良いと言うつもりです。正規表現が絵に描いたように完璧でない場合、あらゆる種類の予測不可能な奇妙さを引き起こす可能性があります。

于 2013-03-02T21:43:46.467 に答える