-1

I have a csv without headers that can have lines in these three following formats:

char,int,int,string,int

char,int,string

char

The first character defines the format and be one of the values (A,B,C) respectively. Does anyone know a way to deserialize it based on the line format?

ES04r3s
  • 29
  • 2
  • 2
    What have you tried, etc – BallpointBen May 16 '22 at 02:44
  • Hm, I'm curious how to best realize that. The [naive approach](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fff8385efd974572636a0380c30daf46) doesn't work. – Caesar May 16 '22 at 02:59

1 Answers1

1

Just keep it simple. You can always parse it manually.

use std::io::{self, BufRead, Error, ErrorKind};

pub enum CsvLine {
    A(i32, i32, String, i32),
    B(i32, String),
    C,
}

pub fn read_lines<R: BufRead>(reader: &mut R) -> io::Result<Vec<CsvLine>> {
    let mut lines = Vec::new();

    for line in reader.lines() {
        let line = line?;

        let trimmed = line.trim();
        if trimmed.is_empty() {
            continue
        }
        
        // Split line by commas 
        let items: Vec<&str> = trimmed.split(',').collect();
        
        match items[0] {
            "A" => {
                lines.push(CsvLine::A (
                    items[1].parse::<i32>().map_err(|e| Error::new(ErrorKind::Other, e))?,
                    items[2].parse::<i32>().map_err(|e| Error::new(ErrorKind::Other, e))?,
                    items[3].to_string(),
                    items[4].parse::<i32>().map_err(|e| Error::new(ErrorKind::Other, e))?,
                ));
            }
            "B" => {
                lines.push(CsvLine::B (
                    items[1].parse::<i32>().map_err(|e| Error::new(ErrorKind::Other, e))?,
                    items[2].to_string(),
                ));
            }
            "C" => lines.push(CsvLine::C),
            x => panic!("Unexpected string {:?} in first column!", x),
        }
    }
    
    Ok(lines)
}

Calling this function would look something like this:

let mut file = File::open("path/to/data.csv").unwrap();
let mut reader = BufReader::new(file);

let lines: Vec<CsvLine> = read_lines(&mut reader).unwrap();

But you may want to keep in mind that I didn't bother to handle a couple edge cases. It may panic if there are not enough items to satisfy the requirements and it makes no attempt to parse more complex strings. For example, "\"quoted strings\"" and "\"string, with, commas\"" would likely cause issues.

Locke
  • 7,626
  • 2
  • 21
  • 41