1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use std::io::Read;
use csv::StringRecord;
use simple_excel_writer::{Column, Row, Sheet, Workbook};
pub mod cli;
mod constants;
use constants::*;
pub struct Options {
delimiter: char,
width_adjustment: bool,
sheet_name: String,
}
impl Options {
pub fn new(
delimiter: Option<char>,
width_adjustment: Option<bool>,
sheet_name: Option<String>,
) -> Self {
Self {
delimiter: delimiter.unwrap_or(DEFAULT_DELIMITER),
width_adjustment: width_adjustment.unwrap_or(DEFAULT_WIDTH_ADJUSTMENT),
sheet_name: sheet_name.unwrap_or_else(|| DEFAULT_SHEET_NAME.to_string()),
}
}
}
fn parse_delimiter(d: char) -> anyhow::Result<u8> {
u8::try_from(u32::from(d)).map_err(anyhow::Error::from)
}
pub fn csv2xlsx<I: Read>(input: I, options: Options) -> anyhow::Result<Vec<u8>> {
let delimiter = parse_delimiter(options.delimiter)?;
let mut reader = csv::ReaderBuilder::new()
.delimiter(delimiter)
.has_headers(false)
.from_reader(input);
let mut workbook = Workbook::create_in_memory();
let mut sheet = workbook.create_sheet(&options.sheet_name);
let mut records = Vec::new();
for result in reader.records() {
let record = result?;
records.push(record);
}
if options.width_adjustment {
adjust_column_widths(&mut sheet, &records)?;
}
workbook.write_sheet(&mut sheet, |sheet_writer| {
for record in records {
let mut row = Row::new();
for value in record.into_iter() {
row.add_cell(value);
}
sheet_writer.append_row(row)?;
}
Ok(())
})?;
let output = workbook.close()?.unwrap();
Ok(output)
}
fn adjust_column_widths(sheet: &mut Sheet, records: &Vec<StringRecord>) -> anyhow::Result<()> {
if records.is_empty() {
return Ok(());
}
let record0 = &records[0];
let mut max_chars: Vec<usize> = record0
.iter()
.map(|cell| cell.char_indices().count() + 3)
.collect();
for record in records {
for (cell_idx, cell) in record.iter().enumerate() {
let char_count = cell.char_indices().count();
let current_max = max_chars.get(cell_idx).unwrap_or(&0).to_owned();
if char_count > current_max {
max_chars[cell_idx] = char_count;
}
}
}
for max in max_chars {
sheet.add_column(Column { width: max as f32 })
}
Ok(())
}