0

Google eBook のトランザクション レポートを解析したいと考えています。ファイルとレコードの区切り文字を正確に確認するために、メモ帳++で開きました。これはタブ区切りのファイルで、すべてのヘッダー フィールドとデータ フィールドは引用符で囲まれています。CSV ファイルの最初の 2 行は次のとおりです。

"Transaction Date" "Id" "Product" "Type" "Preorder" "Qty" "Primary ISBN" "Imprint Name" "Title" "Author" "Original List Price Currency" "Original List Price Currency" "Original List Price Currency" "定価[税込]」「定価[税抜]」「販売国」「発行者収益%」「発行者収益」「支払通貨」「支払金額」「通貨換算率」
「2016.09.01.」"ID:1166315449551685" "単品購入" "セール" "なし" "1" "9789633780664" "Book and Walk Kft" "Bánk bán" "József Katona" "HUF" "0,00" "HUF" "0,00 " "0,00" "HU" "52,0%" "0,00" "" "" ""

次のコードを使用して、CSV ファイルを解析します。

private List<Sales> parseCsv(File csv) {
    Calendar max = Calendar.getInstance();
    Calendar current = Calendar.getInstance();
    boolean firstRound = true;

    List<Sales> sales = new ArrayList<>();
    Sales currentRecord;
    Reader in;
    try {
        in = new FileReader(csv);
        Iterable<CSVRecord> records;

        try {

            records = CSVFormat.TDF.withQuote('\"').withFirstRecordAsHeader().parse(in);
            for (CSVRecord record : records) {
                currentRecord = new Sales();
                currentRecord.setAuthor(record.get("Author"));
                currentRecord.setTitle(record.get("Title"));
                currentRecord.setPublisher(record.get("Imprint Name"));
                currentRecord.setIsbn(record.get("Primary ISBN"));
                currentRecord.setChannel("Google");
                currentRecord.setBookId(record.get("Id"));
                currentRecord.setCountry(record.get("Country of Sale"));
                currentRecord.setUnits(Integer.parseInt(record.get("Qty")));
                currentRecord.setUnitPrice(Float.parseFloat(record.get("List Price [tax exclusive]")));

                Date transDate;
                try {
                    transDate = sourceDateFormat.parse(record.get("Transaction Date"));
                    if (firstRound) {
                        max.setTime(transDate);
                    };
                    current.setTime(transDate);
                    if (current.after(max)) {
                        max.setTime(current.getTime());
                    }
                    currentRecord.setDatum(transDate);
                } catch (ParseException e) {
                    // TODO Auto-generated catch block
                    LOG.log(Level.SEVERE,"Nem megfeelő formátumú a dátum a {0} file-ban",csv.getAbsolutePath());
                }

                currentRecord.setCurrencyCustomer(record.get("List Price Currency"));
                currentRecord.setCurrencyProceeds(record.get("Payment Amount"));
                currentRecord.setCurrencyProceeds(record.get("Payment Currency"));
                sales.add(currentRecord);
            }
            LOG.log(Level.INFO, "Daily sales transactions of {0} were successfully parsed from ",
                    csv.getAbsolutePath());
            return sales;
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            LOG.log(Level.SEVERE, "Valami nem stimmel a {0} file szerkezetével",csv.getAbsolutePath());
        }
    } catch (FileNotFoundException e1) {
        // TODO Auto-generated catch block
        LOG.log(Level.SEVERE,"A {0} file-t nem találom.",csv.getAbsolutePath());
    }
    return null;
};

解析プロセスをデバッグすると、record.get("Author") が実行時例外をスローしたことがわかります。

java.lang.IllegalArgumentException: Mapping for Author not found, expected one of [��"

明らかに、Author という名前の列があります。何がうまくいかないのですか?

4

2 に答える 2

1

これを単体テストに変換し、現在の commons-csv バージョン 1.4 で実行すると、次のようにうまく動作します。

  • commons-csv の最新バージョンで確認する
  • ファイルに実際にタブがあり、何らかの理由で作成者エントリの周りに空白がないことを確認してください
  • 非 ASCII 文字を正しく処理するために parse() を呼び出すときに、ファイルの実際のエンコーディングを指定します (@tonakai からのコメントに感謝します)。

次の単体テストは commons-csv 1.4 で正常に動作します

private final static String DATA = "\"Transaction Date\"\t\"Id\"\t\"Product\"\t\"Type\"\t\"Preorder\"\t\"Qty\"\t\"Primary ISBN\"\t\"Imprint Name\"\t\"Title\"\t\"Author\"\t\"Original List Price Currency\"\t\"Original List Price\"\t\"List Price Currency\"\t\"List Price [tax inclusive]\"\t\"List Price [tax exclusive]\"\t\"Country of Sale\"\t\"Publisher Revenue %\"\t\"Publisher Revenue\"\t\"Payment Currency\"\t\"Payment Amount\"\t\"Currency Conversion Rate\"\n" +
        "\"2016. 09. 01.\"\t\"ID:1166315449551685\"\t\"Single Purchase\"\t\"Sale\"\t\"None\"\t\"1\"\t\"9789633780664\"\t\"Book and Walk Kft\"\t\"Bánk bán\"\t\"József Katona\"\t\"HUF\"\t\"0,00\"\t\"HUF\"\t\"0,00\"\t\"0,00\"\t\"HU\"\t\"52,0%\"\t\"0,00\"\t\"\"\t\"\"\t\"\"";

@Test
public void parseCsv() throws IOException {
    final CSVFormat format = CSVFormat.TDF.withQuote('\"').withFirstRecordAsHeader();
    Iterable<CSVRecord> records = format.parse(new StringReader(DATA));

    System.out.println("Headers: " + Arrays.toString(format.getHeader()));

    for (CSVRecord record : records) {
        assertNotNull(record.get("Author"));
        assertNotNull(record.get("Title"));
        assertNotNull(record.get("Imprint Name"));
        assertNotNull(record.get("Primary ISBN"));
        assertNotNull(record.get("Id"));
        assertNotNull(record.get("Country of Sale"));
        assertNotNull(record.get("Qty"));
        assertNotNull(record.get("List Price [tax exclusive]"));

        assertNotNull(record.get("Transaction Date"));

        assertNotNull(record.get("List Price Currency"));
        assertNotNull(record.get("Payment Amount"));
        assertNotNull(record.get("Payment Currency"));

        System.out.println("Record: " + record.toString());
    }
}
于 2016-10-20T08:39:02.780 に答える
0

エンコーディングが問題の原因であることが判明しました。@tonakai のコメントに基づいて、Google csv レポートのエンコーディングの分析を開始しました。UTF-16 リトル エンディアンでした。私のファイルにはバイトオーダーマークが含まれていたので、「BOMInputStream」を使用してコードを少しリファクタリングする必要がありました。

Reader r = newReader(csv);
CSVParser csvParser= CSVFormat.TDF.withFirstRecordAsHeader().withQuoteMode(QuoteMode.ALL).parse(r);

.....

private InputStreamReader newReader(final File csv) throws FileNotFoundException {
        return new InputStreamReader(new BOMInputStream(new FileInputStream(csv),ByteOrderMark.UTF_16LE), StandardCharsets.UTF_16LE);
    }

それは今働いています

于 2016-11-20T13:40:23.417 に答える