47

私のcsvはSystem.outに読み込まれていますが、スペースのあるテキストは次の行に移動されることに気づきました(戻り値として\ n)

csvの開始方法は次のとおりです。

first,last,email,address 1, address 2
john,smith,blah@blah.com,123 St. Street,
Jane,Smith,blech@blech.com,4455 Roger Cir,apt 2

アプリを実行した後、スペース(アドレス1)のあるセルはすべて次の行にスローされます。

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class main {

    public static void main(String[] args) {
        // -define .csv file in app
        String fileNameDefined = "uploadedcsv/employees.csv";
        // -File class needed to turn stringName to actual file
        File file = new File(fileNameDefined);

        try{
            // -read from filePooped with Scanner class
            Scanner inputStream = new Scanner(file);
            // hashNext() loops line-by-line
            while(inputStream.hasNext()){
                //read single line, put in string
                String data = inputStream.next();
                System.out.println(data + "***");

            }
            // after loop, close scanner
            inputStream.close();


        }catch (FileNotFoundException e){

            e.printStackTrace();
        }

    }
}

したがって、コンソールでの結果は次のとおりです。

最初、最後、メール、アドレス
1、住所
2
john、smith、blah @ blah.com、123
聖。
街、
Jane、Smith、blech @ blech.com、4455
ロジャー
Cir、apt
2

スキャナーを間違って使用していますか?

4

8 に答える 8

159

欠陥のあるCSVパーサーの作成はやめてください。

私は何百ものCSVパーサーと、それらのいわゆるチュートリアルをオンラインで見ました。

それらのほぼすべてがそれを間違えます!

これは私には影響しないのでそれほど悪いことではありませんが、CSVリーダーを書き込もうとして、それを間違えようとする人々は、CSVライターも書く傾向があります。そして、それらも間違えます。そして、これらは私がパーサーを書かなければならないものです。

CSVを覚えておいてください(あまり目立たないように昇順で):

  1. 値を引用符で囲むことができます
  2. 「」以外の引用文字を含めることができます
  3. 「および」以外の引用文字を含めることもできます
  4. 引用文字をまったく含めることはできません
  5. 一部の値には引用符を使用でき、他の値には引用符を使用できません
  6. 、、および;以外の区切り文字を含めることができます。
  7. 区切り文字と(引用符で囲まれた)値の間に空白を含めることができます
  8. アスキー以外の文字セットを持つことができます
  9. 各行に同じ数の値を含める必要がありますが、常にそうであるとは限りません
  10. "foo","","bar"引用符で囲まれた:またはされていない空のフィールドを含めることができます:"foo",,"bar"
  11. 値に改行を含めることができます
  12. 区切り文字でない場合、値に改行を含めることはできません
  13. 値の間に改行を含めることはできません
  14. 適切にエスケープされている場合、値内に区切り文字を含めることができます
  15. 区切り文字をエスケープするために円記号を使用しませんが...
  16. 引用符自体を使用してエスケープします。たとえばFrodo's Ring'Frodo''s Ring'
  17. 値の最初または最後に引用文字を含めることも、文字("foo""", """bar", """")のみとして含めることもできます
  18. 引用符で囲まれていない値の中に引用符で囲まれた文字を含めることもできます。これは逃げられない

これが問題ではないことは明らかだと思う場合は、もう一度考えてみてください。私はこれらの項目のすべてが間違って実装されているのを見きました。主要なソフトウェアパッケージでも。(例:Office-Suites、CRM Systems)

すぐに使える優れたCSVリーダーとライターがあります。

自分で書くことを主張する場合は、少なくともCSVの(非常に短い)RFCを読んでください。

于 2014-07-25T08:01:11.617 に答える
46
scanner.useDelimiter(",");

これは機能するはずです。

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;


public class TestScanner {

    public static void main(String[] args) throws FileNotFoundException {
        Scanner scanner = new Scanner(new File("/Users/pankaj/abc.csv"));
        scanner.useDelimiter(",");
        while(scanner.hasNext()){
            System.out.print(scanner.next()+"|");
        }
        scanner.close();
    }

}

CSVファイルの場合:

a,b,c d,e
1,2,3 4,5
X,Y,Z A,B

出力は次のとおりです。

a|b|c d|e
1|2|3 4|5
X|Y|Z A|B|
于 2013-01-11T08:32:51.100 に答える
10

Scanner.next()改行を読み取りませんが、空白で区切られた次のトークンを読み取ります(デフォルトでuseDelimiter()は、区切りパターンの変更に使用されなかった場合)。行を読み取るには、を使用しますScanner.nextLine()

1行を読んだら、String.split(",")その行をフィールドに分割するために使用できます。これにより、必要な数のフィールドで構成されていない行を識別できます。を使用useDelimiter(",");すると、ファイルの行ベースの構造が無視されます(各行は、コンマで区切られたフィールドのリストで構成されます)。例えば:

while (inputStream.hasNextLine())
{
    String line = inputStream.nextLine();
    String[] fields = line.split(",");
    if (fields.length >= 4) // At least one address specified.
    {
        for (String field: fields) System.out.print(field + "|");
        System.out.println();
    }
    else
    {
        System.err.println("Invalid record: " + line);
    }
}

すでに述べたように、CSVライブラリを使用することをお勧めします。1つは、これ(およびuseDelimiter(",")解決策)は、文字を含む引用符で囲まれた識別子を正しく処理しないこと,です。

于 2013-01-11T08:32:54.737 に答える
1

nextLine()をこの区切り文字で分割します: (?=([^\"]*\"[^\"]*\")*[^\"]*$)")

于 2018-03-08T10:18:11.217 に答える
1

私はScheintodに同意します。既存のCSVライブラリを使用することは、最初からRFC-4180に準拠することをお勧めします。前述のOpenCSVとOsterMillerの他に、他にも一連のCSVライブラリがあります。パフォーマンスに関心がある場合は、uniVocity/csv-parsers-comparisonをご覧ください。それは

JDK 6、7、8、または9のいずれかを使用すると、一貫して最速になります。この調査では、これら3つのいずれにもRFC4180の互換性の問題は見つかりませんでした。OpenCSVとOsterMillerはどちらも、それらの約2倍遅いことがわかっています。

私は著者とはまったく関係がありませんが、uniVocity CSVパーサーに関しては、その著者がそのパーサーと同じであるため、調査にバイアスがかかる可能性があります。

SimpleFlatMapperの作成者は、これら3つだけを比較したパフォーマンス比較も公開しています。

于 2018-07-05T10:10:37.460 に答える
0

コードが引用符( ")、引用符内の改行文字、および引用符内の引用符を処理しないことによって引き起こされる多くの生成上の問題を確認しました。例:"彼は"" this """を解析する必要があります:彼は" this "

前述のように、CSV解析の例の多くは、行を読み取ってから、区切り文字で行を分割します。これはかなり不完全で問題があります。

私とおそらくビルドの詩を好む人のために(または他の誰かのコードを使用してそれらの依存関係を処理する)、私は古典的なテキスト解析プログラミングに取り掛かりました、そしてそれは私のために働きました:

/**
 * Parse CSV data into an array of String arrays. It handles double quoted values.
 * @param is input stream
 * @param separator
 * @param trimValues
 * @param skipEmptyLines
 * @return an array of String arrays
 * @throws IOException
 */
public static String[][] parseCsvData(InputStream is, char separator, boolean trimValues, boolean skipEmptyLines)
    throws IOException
{
    ArrayList<String[]> data = new ArrayList<String[]>();
    ArrayList<String> row = new ArrayList<String>();
    StringBuffer value = new StringBuffer();
    int ch = -1;
    int prevCh = -1;
    boolean inQuotedValue = false;
    boolean quoteAtStart = false;
    boolean rowIsEmpty = true;
    boolean isEOF = false;

    while (true)
    {
        prevCh = ch;
        ch = (isEOF) ? -1 : is.read();

        // Handle carriage return line feed
        if (prevCh == '\r' && ch == '\n')
        {
            continue;
        }
        if (inQuotedValue)
        {
            if (ch == -1)
            {
                inQuotedValue = false;
                isEOF = true;
            }
            else
            {
                value.append((char)ch);

                if (ch == '"')
                {
                    inQuotedValue = false;
                }
            }
        }
        else if (ch == separator || ch == '\r' || ch == '\n' || ch == -1)
        {
            // Add the value to the row
            String s = value.toString();

            if (quoteAtStart && s.endsWith("\""))
            {
                s = s.substring(1, s.length() - 1);
            }
            if (trimValues)
            {
                s = s.trim();
            }
            rowIsEmpty = (s.length() > 0) ? false : rowIsEmpty;
            row.add(s);
            value.setLength(0);

            if (ch == '\r' || ch == '\n' || ch == -1)
            {
                // Add the row to the result
                if (!skipEmptyLines || !rowIsEmpty)
                {
                    data.add(row.toArray(new String[0]));
                }
                row.clear();
                rowIsEmpty = true;

                if (ch == -1)
                {
                    break;
                }
            }
        }
        else if (prevCh == '"')
        {
            inQuotedValue = true;
        }
        else
        {
            if (ch == '"')
            {
                inQuotedValue = true;
                quoteAtStart = (value.length() == 0) ? true : false;
            }
            value.append((char)ch);
        }
    }
    return data.toArray(new String[0][]);
}

単体テスト:

String[][] data = parseCsvData(new ByteArrayInputStream("foo,\"\",,\"bar\",\"\"\"music\"\"\",\"carriage\r\nreturn\",\"new\nline\"\r\nnext,line".getBytes()), ',', true, true);
for (int rowIdx = 0; rowIdx < data.length; rowIdx++)
{
    System.out.println(Arrays.asList(data[rowIdx]));
}

出力を生成します:

[foo, , , bar, "music", carriage
return, new
line]
[next, line]
于 2020-05-07T11:47:12.690 に答える
-1

どうしてもScannerを使用する必要がある場合は、そのuseDelimiter(...)メソッドを使用して区切り文字を設定する必要があります。それ以外の場合は、デフォルトですべての空白を区切り文字として使用します。すでに述べたように、CSVライブラリを使用することをお勧めします。これがCSVライブラリが最も得意とすることだからです。

たとえば、この区切り文字は、空白を囲むかどうかに関係なく、コンマで分割されます。

scanner.useDelimiter("\\s*,\\s*");

詳細については、 java.util.ScannerAPIを確認してください。

于 2013-01-11T08:32:28.327 に答える
-3

さて、私はNetBeans8.1でコーディングを行います。

最初に:新しいプロジェクトを作成し、Javaアプリケーションを選択して、プロジェクトに名前を付けます。

次に、パブリッククラスの後にコードを次のように変更します。

/**
 * @param args the command line arguments
 * @throws java.io.FileNotFoundException
 */
public static void main(String[] args) throws FileNotFoundException {
    try (Scanner scanner = new Scanner(new File("C:\\Users\\YourName\\Folder\\file.csv"))) {
         scanner.useDelimiter(",");
         while(scanner.hasNext()){
             System.out.print(scanner.next()+"|");
         }}
    }
}
于 2016-01-23T15:08:41.557 に答える