【问题标题】:Parsing csv data into object with different column length将csv数据解析为具有不同列长度的对象
【发布时间】:2020-06-12 02:52:37
【问题描述】:

我是 Java 新手,正在练习将 csv 文件解析为对象。我已经试过了,但无法弄清楚。

文件如下所示:

  [0],    [1], [2],    [3]  ,    [4]    ,   [5]   ,  [6] ,   [7]  ,  [8] , [9]
class, gender, age, bodyType, profession, pregnant, isYou ,species, isPet, role
scenario:green,   ,         ,           ,         ,        ,      ,      ,
person, female, 24, average ,           , FALSE   ,        ,      ,      , passenger
animal, male  ,  4,         ,           , FALSE   ,        , dog  , TRUE , pedestrian
scenario:red
person, male  , 16, athletic, boxer     , FALSE   ,  TRUE  ,      ,      , passenger
person, female, 25, athletic, doctor    , TRUE    ,  FALSE ,      ,      , pedestrian

我需要在任何场景下由任意数量的乘客和行人解析它。最后将这些场景加入到一个ArrayList中进行分析。

我的想法是:

  1. 循环遍历每一行,到达下一个scenario:red时停止,将乘客和行人添加到Character ArrayList。 (我已经添加了,但不知道如何停止)。
  2. 使用构造函数scenario(ArrayList<Character> passenger, ArrayList<Character> pedestrians, boolean redOrGreen); 创建一个scenario
  3. ArrayList scenarios 添加创建的场景。

我所做的是将所有内容放在一起而不是将它们分开。非常感谢任何帮助或提示。

感谢这个帮助我的社区,这是我目前所得到的。

    public void loadCsv() throws IOException {

    String csvFile = "config.csv";
    String line = "";
    String csvSplit = "\\s*,\\s*";

    Scenario scenario = new Scenario();
    Person person = new Person();
    Animal animal = new Animal();

    ArrayList<Scenario> scenaios = new ArrayList<Scenario>();
    ArrayList<String> csvContents = new ArrayList<String>();

    ArrayList<Character> passengers = new ArrayList<Character>();
    ArrayList<Character> pedestrians = new ArrayList<Character>();

    try (BufferedReader csvReader = new BufferedReader(new FileReader(csvFile));) {
        String headerLine = csvReader.readLine(); //get rid of the header
        //add each line to the arrayList
        while ((line = csvReader.readLine()) != null) { 
            csvContents.add(line);   
        }

        for(String csvLine : csvContents) {                
            String[] data = csvLine.split(csvSplit); // split by comma and remove redundant spaces

            if (data.length == NO_OF_FIELD) { //check and avoid indexOutOfBoundException

                String clazz = data[0].toLowerCase();// cannot use word "class" as a variable

                if (clazz.startsWith("scenario") && data.length == 1) { 
                    scenario = new Scenario();
                    scenario.setLegalCrossing(clazz.endsWith("green"));
                    continue;
                } 

                else if ("person".equals(clazz) && data.length ==10) {

                    person = loadCsvPerson(data);
                    addCharacter(person, data);

                } 

                else if ("animal".equals(clazz) && data.length ==10) {

                    animal = loadCsvAnimal(data);
                    addCharacter(animal, data);

                    }                        
                }
            }                               
        }
        //passenger and pedestrians are in position
        System.out.println("passengers: " + passengers);
        System.out.println("pedestrians: " + pedestrians);

        if (null != scenario) {
            scenario.setPassengers(passengers);
            scenario.setPedestrians(pedestrians);
        }

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } 
}

【问题讨论】:

标签: java parsing


【解决方案1】:

如果可以更改 csv 文件格式,我会添加场景类型列(如果需要,还可以添加场景 ID 或名称),这样您可以在连接表时将 csv 文件作为数据库的结果集(场景 +乘客 + 行人)并返回普通行。

使用这种方法,您将能够将解析委托给任何 csv 库并单独执行您的逻辑(按场景 ID/名称/类型分组)。使用代理行(场景:绿色...),您必须编写自定义解析器。

例如,您可以使用univocity 将文件简单地解析到您的模型中(甚至使用注释)并迭代地对其进行分组和处理。

【讨论】:

  • 谢谢您,先生!看起来不错,但遗憾的是,我不允许更改 csv 的格式。 @艺术
  • 我会尽量简化这个问题的结构,去掉不相关的信息。谢谢你,先生。
  • 如果文件结构是预定义的,当看到新的场景时,你必须停止收集乘客和行人。所以在做之前场景 = new Scenario();您必须将所有收集的行人和乘客添加到当前场景(如果它不为空)并将其添加到场景列表中。只有在此之后,您才能创建下一个场景并为乘客和行人定义新列表
  • 是的,我就是这么想的,但是我很难把我的想法变成我的程序。
【解决方案2】:

或者,如果您需要使用现有文件格式,请执行以下操作:

if (clazz.startsWith("scenario") && data.length == 1) { 
    // collect existing scenario before starting processing new one
    if (scenario != null) {
        scenario.setPassengers(passengers);
        scenario.setPedestrians(pedestrians);

        passengers = new ArrayList();
        pedestrians = new ArrayList();

        scenarios.add(scenario);
    }

    // now start new group (scenario)
    scenario = new Scenario();
    scenario.setLegalCrossing(clazz.endsWith("green"));
    continue;
} 

【讨论】:

  • 最后一组数据不会被解析,我会在arrayList中有一个空的scenario。但是,先生,谢谢您审查我的代码
【解决方案3】:

您的代码中需要解决以下问题:

  1. 尽量避免使用标准库已经使用的类名(尤其是在默认包中时,java.lang),例如Java 库中已经有一个类 Character,因此您应该为您的自定义类使用不同的名称。

  2. 使用continue跳过行,scenario:red

    for(String csvLine : csvContents) { 
        if(csvLine.equals("scenario:red")){
            continue;
        }
        String[] data = csvLine.split(csvSplit); // split by comma and remove redundant spaces
    
        if (data.length == NO_OF_FIELD) {
            //..
        }
        //..
    }
    
  3. 如果您已经定义了final int NO_OF_FIELD = 10,您可以使用相同的值而不是直接使用值10,即您应该在以下代码中使用NO_OF_FIELD 而不是10

    if (data.length == NO_OF_FIELD) { //check and avoid indexOutOfBoundException
    
        String clazz = data[0].toLowerCase();// cannot use word "class" as a variable
    
        //...
    
        else if ("person".equals(clazz) && data.length ==10) {
    

    但是,您还需要了解这里不需要&amp;&amp; data.length ==10,因为您已经在封闭的if 条件中检查了data.length == NO_OF_FIELD

我无法理解您的其余观点。如果您澄清它们,我将能够为您提供进一步的帮助。

【讨论】:

  • 谢谢您,先生。我很感激你愿意再次提供帮助。我需要将这两种标记scenario:greenscenario:red 抓取到场景构造函数中。例如,当我有scenario:green 时,我需要在downside 添加一组乘客和行人,并在构造函数scenario(passenger[], pedestrian[], boolean greenOrRed) 中将它们包裹在一起。而当遇到另一个令牌scenario:red时,也是同样的操作,收集乘客和行人直到下一个scenario:greenscenario:red
  • 谢谢您,先生。我想通了。
【解决方案4】:

我需要在第二轮添加之前的scenario。 由于最后一组数据不会被捕获,我需要设置另一个新的scenario 来添加它。感谢艺术先生。

Character character = null;
    try (BufferedReader csvReader = new BufferedReader(new FileReader(csvFile));) {
        String headerLine = csvReader.readLine(); //get rid of the header
        //add each line to the arrayList
        while ((line = csvReader.readLine()) != null) { 
            csvContents.add(line);   
        }
        final int NO_OF_FIELDS = 10;

        for(String csvLine : csvContents) {                
            String[] data = csvLine.split(csvSplit); // split by comma and remove redundant spaces                
            String clazz = data[0].toLowerCase();// cannot use word "class" as a variable

            if (clazz.startsWith("scenario") && data.length == 1) {
                // adding scenario after one set of data
                // i.e second round adding the first round data
                if (passengers.size() != 0 && pedestrians.size() != 0) {
                    Scenario scenario = new Scenario();
                    scenario.setPassengers(passengers);
                    scenario.setPedestrians(pedestrians);
                    scenarios.add(scenario);
                }

                passengers = new ArrayList<Character>();
                pedestrians = new ArrayList<Character>();

                if (clazz.endsWith("green")) {
                    scenario.setLegalCrossing(true);
                    System.out.println("green light");
                }

                else if (clazz.endsWith("red")){
                    scenario.setLegalCrossing(false);
                    System.out.println("red light");
                } 

                continue;
            }
        //...
            Scenario scenario = new Scenario();
            scenario.setPassengers(passengers);
            scenario.setPedestrians(pedestrians);
            scenarios.add(scenario);

            scenario.setPassengers(passengers);
            scenario.setPedestrians(pedestrians);

            Audit audit = new Audit();
            audit.setScenario(scenarios);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    • 1970-01-01
    • 2020-04-08
    • 2021-07-14
    • 1970-01-01
    相关资源
    最近更新 更多