Univocity - 不规则csv解析

3

我需要解析不规则(尽管一致)的“csv”文件。文件内容如下所示:

Field1: Field1Text
Field2: Field2Text

Field3 (need to ignore)
Field4 (need to ignore)

Field5
Field5Text

// Cars - for example
#,Col1,Col2,Col3,Col4,Col5,Col6
#1,Col1Text,Col2Text,Col3Text,Col4Text,Col5Text,Col6Text
#2,Col1Text,Col2Text,Col3Text,Col4Text,Col5Text,Col6Text
#3,Col1Text,Col2Text,Col3Text,Col4Text,Col5Text,Col6Text

理想情况下,我希望采用类似于这里的方法。
最终,我想要得到一个像这样的对象:
String field1;
String field2;
String field5;
List<Car> cars;

我目前有以下问题:

  • 添加了一些探索性测试后,以#开头的行将被忽略。我不想这样,有没有办法进行转义?
  • 我的意图是在汽车部分使用BeanListProcessor,并使用单独的行处理器处理其他字段。然后将结果合并到上述对象中。我是否漏掉了任何技巧?
1个回答

1

您遇到的第一个问题是 # 默认被视为注释字符。要防止以 # 开头的行被视为注释,请执行以下操作:

parserSettings.getFormat().setComment('\0');

关于您正在解析的结构,没有现成的方法可以完成,但很容易利用API来实现。以下内容可行:

    CsvParserSettings settings = new CsvParserSettings();
    settings.getFormat().setComment('\0'); //prevent lines starting with # to be parsed as comments

    //Creates a parser
    CsvParser parser = new CsvParser(settings);

    //Open the input
    parser.beginParsing(new File("/path/to/input.csv"), "UTF-8");

    //create BeanListProcessor for instances of Car, and initialize it.
    BeanListProcessor<Car> carProcessor = new BeanListProcessor<Car>(Car.class);
    carProcessor.processStarted(parser.getContext());

    String[] row;
    Parent parent = null;
    while ((row = parser.parseNext()) != null) { //read rows one by one.
        if (row[0].startsWith("Field1:")) {  // when Field1 is found, create your parent instance
            if (parent != null) { //if you already have a parent instance, cars have been read. Associate the list of cars to the instance
                parent.cars = new ArrayList<Car>(carProcessor.getBeans()); //copy the list of cars from the processor.
                carProcessor.getBeans().clear(); //clears the processor list
                //you probably want to do something with your parent bean here.
            }
            parent = new Parent(); //create a fresh parent instance
            parent.field1 = row[0]; //assign the fields as appropriate.
        } else if (row[0].startsWith("Field2:")) {
            parent.field2 = row[0]; //and so on
        } else if (row[0].startsWith("Field5:")) {
            parent.field5 = row[0];
        } else if (row[0].startsWith("#")){ //got a "Car" row, invoke the rowProcessed method of the carProcessor.
            carProcessor.rowProcessed(row, parser.getContext());
        }
    }

    //at the end, if there is a parent, get the cars parsed
    if (parent != null) {
        parent.cars = carProcessor.getBeans();
    }

为了让BeanListProcessor正常工作,您需要像这样声明实例:
public static final class Car {
    @Parsed(index = 0)
    String id;
    @Parsed(index = 1)
    String col1;
    @Parsed(index = 2)
    String col2;
    @Parsed(index = 3)
    String col3;
    @Parsed(index = 4)
    String col4;
    @Parsed(index = 5)
    String col5;
    @Parsed(index = 6)
    String col6;
}

您可以使用标题来代替,但这会使您编写更多的代码。如果标题始终相同,则可以假定位置是固定的。
希望这可以帮到您。

感谢您抽出时间回答Jeronimo。我也非常喜欢使用解析器! - Hurricane

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接