【问题标题】:Ignoring delimiter in quote-enclosed field in Apache Commons CSV / OpenCSV?忽略Apache Commons CSV / OpenCSV中引号括起来的字段中的分隔符?
【发布时间】:2016-11-14 21:57:26
【问题描述】:

我必须解析一个 csv 文件,该文件的字段如下所示:

("FOO, BAR BAZ", 42)

并产生两个字段:

FOO, BAR BAZ  
42

我不确定如何使用 Apache Commons CSV 或 OpenCSV 简洁地做到这一点,所以我正在寻找一些指导。可能只是我不完全理解org.apache.commons.csv.CSVFormat 属性“quoteChar”which is touched on in the documentation,但在我能找到的任何地方都没有清楚地解释过。如果是这样,如果您能向我指出有关该功能的更好文档,那将非常有帮助。

这是一个简短的示例,显示了我的问题以及我尝试过的方法和结果:

        String test = "(\"FOO, BAR BAZ\", 42)";
        int numTries = 5;
        CSVParser[] tries = new CSVParser[numTries];
        tries[0] = CSVParser.parse(line, CSVFormat.DEFAULT.withRecordSeparator("\n"));//BAR BAZ"
        tries[1] = CSVParser.parse(line, CSVFormat.DEFAULT.withQuote('"'));//BAR BAZ"
        tries[2] = CSVParser.parse(line, CSVFormat.DEFAULT.withQuote(null));//BAR BAZ"
        tries[3] = CSVParser.parse(line, CSVFormat.DEFAULT.withQuote('"').withQuoteMode(QuoteMode.NON_NUMERIC));//BAR BAZ"
        tries[4] = CSVParser.parse(line, CSVFormat.DEFAULT.withRecordSeparator(")\n("));//BAR BAZ"

        for(int i = 0; i < numTries; i++){
            CSVRecord record = tries[i].getRecords().get(0);
            System.out.println(record.get(1));//.equals("42"));
        }  

请注意,如果您从输入中排除括号,它会正常工作。

【问题讨论】:

    标签: java csv noclassdeffounderror apache-commons apache-commons-csv


    【解决方案1】:

    可以使用OpenCSVCSVReader读取数据,获取数据元素如下图:

    public static void main(String[] args) {
        try(FileReader fr = new FileReader(new File("C:\\Sample.txt"));
                    CSVReader csvReader = new CSVReader(fr);) {
                String[] data = csvReader.readNext();
                for(String data1 : data) {
                    System.out.println(data1);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    【讨论】:

    • 它会忽略默认情况下用引号括起来的分隔符吗?
    • 因为这就是我的问题所在。
    【解决方案2】:

    您可以使用 opencsv 实现此目的,如下所示:

    import com.opencsv.CSVReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class NewClass1 {
        public static void main(String[] args) throws IOException {
            String fileName = "C:\\yourFile.csv";
            String [] nextLine;
            // use the three arg constructor to tell the reader which delimiter you have in your file(2nd arg : here ',')                                                          
            // you can change this to '\t' if you have tab separeted file or ';' or ':' ... whatever your delimiter is
            // (3rd arg) '"' if your fields are double quoted or '\'' if single quoted or no 3rd arg if the fields are not quoted
            CSVReader reader = new CSVReader(new FileReader(fileName), ',' ,'"');
            // nextLine[] is an array of values from the line
            // each line represented by String[], and each field as an element of the array
            while ((nextLine = reader.readNext()) != null) {        
                System.out.println("nextLine[0]: " +nextLine[0]);
                System.out.println("nextLine[1]: " +nextLine[1]);
            }
        }
    }
    

    【讨论】:

    • 即使只引用了一些字段(即字符串字段),这是否有效?
    【解决方案3】:

    对我来说,commons-csv 的默认格式对于格式正确的 CSV 消息是正确的:

        Reader in = new StringReader("\"FOO, BAR BAZ\", 42");
        Iterable<CSVRecord> records = CSVFormat.DEFAULT.parse(in);
        for (CSVRecord record : records) {
            for(int i = 0;i < record.size();i++) {
                System.out.println("At " + i + ": " + record.get(i));
            }
        }
    

    导致:

    At 0: FOO, BAR BAZ
    At 1:  42
    

    对于特殊格式的行,您可能需要做更多处理,顶部删除那些括号:

        BufferedReader lineReader = new BufferedReader(
                new StringReader("(\"FOO, BAR BAZ\", 42)\n(\"FOO, BAR FOO\", 44)"));
    
        while(true) {
            String line = lineReader.readLine();
            if (line == null) {
                break;
            }
    
            String adjustedLine = line.substring(1, line.length() - 1);
            records = CSVFormat.DEFAULT.parse(new StringReader(adjustedLine));
            for (CSVRecord record : records) {
                for (int i = 0; i < record.size(); i++) {
                    System.out.println("At " + i + ": " + record.get(i));
                }
            }
        }
    

    【讨论】:

    • 这是我的预期,但是我得到了invalid char between encapsulated token and delimiter 和解决方案here 建议更改 withQuote 来修复它。
    • 可以在您的问题中包含一个最小的测试用例吗?因为我看不出你的代码有什么不同,所以我的代码和我发布的完全一样,没有报告任何错误。至少检查您的文本中有哪些引号,如果它们是“印刷引号”,它可能会失败,例如在 Word 中添加。
    • 啊,我明白了。您的输入行周围没有括号。不过可能是我的错——他们最初被排除在外。不过,我已经添加了一个测试用例。
    • 在进行 CSV 解析之前,您需要手动拆分行并删除这些括号,可能没有一个库允许解析这样的内容...
    猜你喜欢
    • 1970-01-01
    • 2022-01-26
    • 2018-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-14
    • 1970-01-01
    • 2020-01-25
    相关资源
    最近更新 更多