Десериализация CSV с помощью Serde, когда в строке заголовка может отсутствовать имя последнего столбца - PullRequest
3 голосов
/ 10 апреля 2019

Я использую ящики csv и serde для десериализации CSV-файлов. Дело в том, что последнее поле - это список, разделенный запятыми.

field1,field2,field3
xx, xx, str1, ..., strN
xx, xx,
xx, xx, str1, ..., strM

А вот как он отображается в Rust, читая его с .flexible(true) на считывателе:

#[derive(Debug, Deserialize)]
struct Row {
  field1: isize,
  field2: isize,
  field3: Vec<String>,
}

Все работает нормально, если CSV имеет ,field3 строку заголовка. Но некоторые файлы не имеют его, и я не могу найти решение, чтобы serde по-прежнему заполнял Vec. Все, что я смог сделать, это #[serde(default)], который просто позволил field3 опустеть.

Здесь ржавчина Детская площадка Показывает проблему:

extern crate csv;
#[macro_use]
extern crate serde_derive;

#[derive(Debug, Deserialize)]
struct Row {
    field1: String,
    field2: String,
    #[serde(default)]
    field3: Vec<String>,
}

fn test(str: String) {
    let mut reader = csv::ReaderBuilder::new()
        .flexible(true)
        .from_reader(str.as_bytes());

    for row in reader.deserialize() {
        if let Ok(row) = row {
            let row: Row = row;
            println!("{:?}", row);
        }
    }
}

fn main() {
    let csv_data = "
field1,field2,field3
xx,yy,one,two,three
zz,ww,
aa,bb
cc,dd,foo,bar,ban
";
    println!("With full header");
    test(csv_data.to_string());

    let csv_alt_data = "
field1,field2
xx,yy,one,two,three
zz,ww,
aa,bb
cc,dd,foo,bar,ban
";
    println!("With incomplet header");
    test(csv_alt_data.to_string());
}

1 Ответ

3 голосов
/ 10 апреля 2019

Добавьте заголовок поля рукой перед тем, как это будут прочитаны строки, используя headers() и set_headers():

let rdr = reader.headers().unwrap();
if let None = rdr.get(2) {
    let mut rdr = rdr.clone();
    rdr.push_field("field3");
    reader.set_headers(rdr);
}

Однако этобыстро и грязно.

...