1

I am new to java and practicing parsing csv file. I've figured out how to parse and use a constructor to create an instance. However, there are empty strings in my csv file, and the console just throw IllegalArgumentException: No enum constant to me.

I've referred to:

  1. enum valueOf IllegalArgumentException: No enum const class
  2. Parse CSV file in java, and delaing with empty values

Unfortunately, it doesn't work. When it comes to the Person with empty Profession, the program breaks. Do I need to fill some string like "NONE" for matching the enum, or there is any way to deal with this? Any help or hint is highly appreciated.

Here is my Profession for example:

public enum Profession {
    DOCTOR, CEO, CRIMINAL, HOMELESS, UNEMPLOYED, MUSICIAN, BOXER , UNKNOWN, NONE;
}

Here is how my csv file looks like:

  [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
  .
  .

Here is the parsing code:

try (BufferedReader csvReader = new BufferedReader(new FileReader(csvFile));) {
String headerLine = csvReader.readLine(); //get rid of header

while ((line = csvReader.readLine()) != null) { 
    csvContents.add(line);// add the line to the ArrayList      
}

for (String csvLine : csvContents) {

    // split by comma and remove redundant spaces
    String[] data = csvLine.split(",",-1); 
    System.out.println(data[1]);// IndexOutOfBound

    Character character = null;
    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) {
        Profession professionEnum = Profession.valueOf(data[4].toUpperCase().trim());  
        Gender genderEnum = Gender.valueOf(data[1].toUpperCase().trim());
        BodyType bodyTypeEnum =BodyType.valueOf(data[3].toUpperCase().trim());

        person = new Person(Integer.parseInt(data[2]), professionEnum ,genderEnum , bodyTypeEnum , Boolean.parseBoolean(data[5]));
        person.setAsYou(Boolean.parseBoolean(data[6]));

    } else if ("animal".equals(clazz)) {
        Gender genderEnum = Gender.valueOf(data[1].toUpperCase().trim());
        BodyType bodyTypeEnum =BodyType.valueOf(data[3].toUpperCase().trim());

        animal = new Animal(Integer.parseInt(data[2]) , genderEnum , bodyTypeEnum, data[7]);
        animal.setIsPet(Boolean.parseBoolean(data[8]));
    }
} catch (someException e) {
  e.printStackTrace();
}

and the parsed line looks like:

scenario:green,,,,,,,,,
person,female,24,average,doctor,false,false,,,passenger
person,male,40,overweight,unknown,false,false,,,passenger
person,female,2,average,,false,false,,,passenger
person,male,82,average,,false,false,,,pedestrian
person,female,32,average,ceo,true,false,,,pedestrian
person,male,7,athletic,,false,false,,,pedestrian
animal,male,4,,,false,false,dog,true,pedestrian
scenario:red,,,,,,,,,
Woden
  • 1,054
  • 2
  • 13
  • 26

2 Answers2

1

Do it as follows:

final int NO_OF_FIELDS = 10;
for (String csvLine : csvContents) {

    // split by comma and remove redundant spaces
    String[] data = csvLine.split(",", -1);
    if (data.length == NO_OF_FIELDS) {// <---Add this check to avoid ArrayIndexOutOfBoundsException
        System.out.println(data[1]);

        Character character = null;
        String clazz = data[0].trim().toLowerCase();// <---Trim to get rid of leading and trailing space

        if (clazz.startsWith("scenario" && data.length == 1)) {
            // ...
        } else if ("person".equals(clazz) && data.length == 10) {
            // Handle the exception as shown below
            Profession professionEnum;
            try {
                professionEnum = Profession.valueOf(data[4].trim().toUpperCase());// <---First trim then apply
                                                                                    // toUpperCase()
            } catch (IllegalArgumentException e) {
                professionEnum = Profession.UNKNOWN;
            }

            // ...

        } else if ("animal".equals(clazz)) {
            // ...
        }
    }
}
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • Thank you for your kindness, sir. It works and I can go further. Is it very late in your time zone? Have a nice day, sir. @Arvind – Woden Jun 11 '20 at 10:57
  • 1
    @Woden - You are most welcome. No, it's not late in my timezone. I'm in the UK and it's 12:00 pm now. – Arvind Kumar Avinash Jun 11 '20 at 10:59
  • Sir, I got a question about this. If I set the field of 9 (actually 10), it seems that the code inside won't be executed. And I have another question of how can I stop before `scenario:red` and set it into one `scenario` object. I've posted this, and stilling trying, but cannot figure out. Thank you, sir. https://stackoverflow.com/questions/62336742/parsing-csv-data-into-object-with-certain-condition-in-java – Woden Jun 12 '20 at 09:27
0

If you later hit a problem with quoted string tokens then you could use OpenCSV library or more csv compliant reader loop. See this example.

List<String> tokens = new ArrayList<String>(32);
String line;
while( (line=fileReader.readLine())!=null) {
    line=line.trim();
    if(line.isEmpty()) continue;
    tokens.clear();
    if (parseCSVLine(tokens, line, ',')>0) {
        for(int idx=0; idx<tokens.size(); idx++)
            System.out.print("|"+tokens.get(idx));
        System.out.println("|");
    }
}

- - - - 
public static int parseCSVLine(List<String> tokens, String line, char delim) {
    // this handles quoted string and tuple "" escape values,
    // array string is returned as a ["drama","comedy"] string value, reader must split to sub tokens.
    // ABCD, "string value", "string "" escape value", "[""drama"",""comedy""]", DEFG       
    int count=0;
    line = line+delim;
    final int maxIdx = line.length()-1;
    int startIdx=0, endIdx=-1; // both inclusive index
    boolean inQuote=false;
    for(int idx=0; idx<=maxIdx; idx++) {
        char ch = line.charAt(idx);
        if(ch==delim && !inQuote) {
            count++;
            //if(line.charAt(startIdx)=='"') startIdx++; // drop leading and trailing " string delimiter
            //if(line.charAt(endIdx)=='"') endIdx--;                
            String value = startIdx<=endIdx ? line.substring(startIdx, endIdx+1).trim() : ""; // trim tokens
            value = value.replace("\"\"", "\""); // convert "" -> "
            tokens.add(value);
            startIdx=idx+1;
            //endIdx=startIdx-1; // use -1
            inQuote=false;
        } else if(ch=='"') {
            if(idx<maxIdx && line.charAt(idx+1)=='"') {
                endIdx+=2; // tuple "" inside the quoted string value
                idx++;
            } else if(!inQuote) {
                inQuote=true; // start quoted string
                startIdx=idx+1; // drop leading " from the token
                //endIdx=startIdx;
            } else {
                inQuote=false; // end quoted string
                endIdx=idx-1;                   
            }
        } else {
            endIdx=idx; // "increment" endIdx, inclusive index to the last char of token
        }           
    }       
    return count;
}
Whome
  • 10,181
  • 6
  • 53
  • 65