fonctionne avec builder to_csv()

refactor
Nicolas Sanchez 4 weeks ago
parent 9dd247b20c
commit 6d446b4767

@ -1 +0,0 @@
,sanchezn,pc-sanchezn,17.02.2026 15:16,/home/sanchezn/.local/share/onlyoffice;

2864
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -3,10 +3,13 @@ name = "xlsxtocsv"
version = "0.1.0"
edition = "2024"
[features]
csv = []
[dependencies]
clap = { version = "4.5.48", features = ["derive"] }
polars = {version = "0.53.0", optional = true}
rhai = "1.23.6"
umya-spreadsheet = "2.3.3"
[features]
default = ["csv"]
csv = []
lazyframe = ["dep:polars"]

Binary file not shown.

@ -4,13 +4,15 @@ use std::fmt;
pub enum Error {
Msg(String),
XlsxError(String),
IoError(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Msg(msg) => write!(f, "{msg}"),
Error::Msg(msg) => write!(f, "XlsxToCsvError: {msg}"),
Error::XlsxError(msg) => write!(f, "XlsxError: {msg}"),
Error::IoError(msg) => write!(f, "IoError: {msg}"),
}
}
}
@ -32,3 +34,9 @@ impl From<String> for Error {
Error::Msg(value)
}
}
impl From<std::io::Error> for Error {
fn from(value: std::io::Error) -> Self {
Error::IoError(value.to_string())
}
}

@ -5,3 +5,6 @@ pub mod xlsx_builder;
//#[cfg(feature = "csv")]
pub mod xlsx_to_csv;
#[cfg(feature = "lazyframe")]
pub mod xlsx_to_lazyframe;

@ -1,14 +1,9 @@
use xlsxtocsv::{arguments::Arguments, xlsx::XlsxReader};
use xlsxtocsv::{error::Error, xlsx::XlsxReader, xlsx_to_csv::Output};
fn main() {
let args = Arguments::parse();
/* if let Err(error) = xlsxtocsv(&args) {
eprintln!("{}", error);
}*/
fn main() -> Result<(), Error> {
XlsxReader::new("noms.xlsx")
.with_active_worksheet()
.to_csv(Output::Stdout)?;
let xlsxreader = XlsxReader::new(args).unwrap();
let reader = xlsxreader.to_csv();
for line in reader {
println!("{line}");
}
Ok(())
}

@ -6,35 +6,32 @@ use umya_spreadsheet::{Cell, Range, Spreadsheet, Worksheet, reader};
use crate::arguments::{Arguments, IntoArgs, NumberRows, TrimSpaces};
use crate::error::Error;
#[derive(Debug, Clone)]
pub struct XlsxReader {
pub(crate) args: Arguments,
pub(crate) book: Spreadsheet,
pub(crate) sheet_index: usize,
pub(crate) book: Option<Spreadsheet>,
pub(crate) sheet_index: Option<usize>,
pub worksheet_dimensions: RefCell<Option<(u32, u32)>>,
}
impl XlsxReader {
pub fn new(args: impl IntoArgs) -> Result<Self, Error> {
let mut args = args.into_args();
pub fn new(args: impl IntoArgs) -> Self {
let args = args.into_args();
let book = reader::xlsx::read(Path::new(args.file.as_str()))?;
if args.active_worksheet && args.worksheet == "0" {
let sheetname = book.get_active_sheet().get_name();
args.worksheet = String::from(sheetname);
}
let sheet_index = Self::get_worksheet_index(&book, args.worksheet.as_str())?;
Ok(XlsxReader {
XlsxReader {
args,
book,
sheet_index,
book: None,
sheet_index: None,
worksheet_dimensions: RefCell::new(None),
})
}
}
pub fn list_worksheets(&self) -> Result<Vec<(usize, String)>, Error> {
let sheets = self.book.get_sheet_collection();
let book = match &self.book {
Some(book) => book,
None => return Err("Call finish before list_worksheets.".into()),
};
let sheets = book.get_sheet_collection();
let mut res = vec![];
for (i, sheet) in sheets.iter().enumerate() {
@ -43,9 +40,19 @@ impl XlsxReader {
Ok(res)
}
pub fn to_lazyframe(&self) {
let sheet = self.get_sheet();
println!("sheetname: {}", sheet.get_name());
pub(crate) fn finish(&mut self) -> Result<(), Error> {
let book = reader::xlsx::read(Path::new(self.args.file.as_str()))?;
if self.args.active_worksheet && self.args.worksheet == "0" {
let sheetname = book.get_active_sheet().get_name();
self.args.worksheet = String::from(sheetname);
}
let sheet_index = Self::get_worksheet_index(&book, self.args.worksheet.as_str())?;
self.book = Some(book);
self.sheet_index = Some(sheet_index);
Ok(())
}
pub(crate) fn get_worksheet_index(
@ -70,16 +77,21 @@ impl XlsxReader {
Ok(sheet_index)
}
pub(crate) fn get_sheet(&self) -> &Worksheet {
self.book.get_sheet(&self.sheet_index).unwrap()
pub(crate) fn get_sheet(&self) -> Result<&Worksheet, Error> {
let book = match &self.book {
Some(book) => book,
None => return Err("Call finish before get_sheet.".into()),
};
Ok(book.get_sheet(&self.sheet_index.unwrap()).unwrap())
}
pub(crate) fn get_worksheet_dimensions(&self) -> (u32, u32) {
if self.worksheet_dimensions.borrow().is_none() {
let mut num_cols = 0;
let mut num_rows = 0;
let sheet = self.get_sheet().unwrap();
for cell in self.get_sheet().get_cell_collection() {
for cell in sheet.get_cell_collection() {
let value = get_value(cell); //.get_formatted_value();
if value.is_empty() {
@ -105,16 +117,16 @@ impl XlsxReader {
pub(crate) fn get_row(&self, row_num: u32) -> Vec<String> {
let num_cols = self.get_worksheet_dimensions().0 as usize;
let sheet = self.get_sheet();
let sheet = self.get_sheet().unwrap();
let row = sheet.get_collection_by_row(&row_num);
let mut res = vec![String::new(); num_cols];
for cell in row {
let txt = cell.get_formatted_value();
let value = cell.get_formatted_value();
let coord = cell.get_coordinate();
let col = *coord.get_col_num() - 1;
res[col as usize] = txt;
res[col as usize] = value;
}
res
@ -316,6 +328,7 @@ fn number_row(number_row: &NumberRows, separator: char, seqrownum: u32, i: u32)
}
fn get_value(cell: &Cell) -> String {
//cell.get_formatted_value()
match cell.get_raw_value() {
umya_spreadsheet::CellRawValue::String(val) => String::from(val.clone()),
umya_spreadsheet::CellRawValue::RichText(text) => (*text.get_text()).to_owned(),

@ -1,6 +1,5 @@
use crate::{
arguments::{FillMergedCells, IncludeHidden, NumberRows, TrimSpaces},
error::Error,
xlsx::XlsxReader,
};
@ -59,15 +58,14 @@ impl XlsxReader {
self
}
pub fn with_worksheet(mut self, worksheet_name: &str) -> Result<Self, Error> {
pub fn with_worksheet(mut self, worksheet_name: &str) -> Self {
self.args.worksheet = String::from(worksheet_name);
self.sheet_index = Self::get_worksheet_index(&self.book, worksheet_name)?;
Ok(self)
self
}
pub fn with_active_worksheet(mut self, active_worksheet: bool) -> Self {
self.args.active_worksheet = active_worksheet;
pub fn with_active_worksheet(mut self) -> Self {
self.args.active_worksheet = true;
self
}
@ -91,6 +89,11 @@ impl XlsxReader {
self
}
pub fn with_trim(mut self, trim: TrimSpaces) -> Self {
self.args.trim = trim;
self
}
pub fn with_number_rows(mut self, number_rows: NumberRows) -> Self {
self.args.number_rows = number_rows;
self

@ -1,35 +1,120 @@
use crate::xlsx::XlsxReader;
use std::{
fs::File,
io::{BufWriter, Write, stderr, stdout},
};
pub struct XlsxToCsvLines<'a> {
xlsx_reader: &'a XlsxReader,
use crate::{error::Error, xlsx::XlsxReader};
#[derive(Clone, Debug)]
pub struct XlsxToCsvLines {
xlsx_reader: XlsxReader,
current_row: u32,
num_rows: u32,
separator: String,
end_of_line: String,
}
impl<'a> Iterator for XlsxToCsvLines<'a> {
type Item = String;
impl Iterator for XlsxToCsvLines {
type Item = Result<String, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.current_row > self.num_rows {
return None;
}
let row = self.xlsx_reader.get_row(self.current_row);
let mut row = self.xlsx_reader.get_row(self.current_row);
match &self.xlsx_reader.args.replace_separator_by {
Some(replacement) => {
row = row
.iter()
.map(|v| v.replace(self.xlsx_reader.args.separator, replacement.as_str()))
.collect()
}
None => {
if row
.iter()
.any(|v| v.contains(self.xlsx_reader.args.separator))
{
return Some(Err(
"Some cells contains the separator char. Use a replacement for separator char inside cells.".into(),
));
}
}
}
self.current_row += 1;
let row = row.join(";");
let mut row = row.join(self.separator.as_str());
match &self.xlsx_reader.args.replace_end_of_line_by {
Some(replacement) => row = row.replace(self.end_of_line.as_str(), replacement),
None => {
if row.contains(self.end_of_line.as_str()) {
return Some(Err("Some cells contains the end of line char. Use a replacement for end of line char inside cells.".into()));
}
}
}
let row = row + self.end_of_line.as_str();
Some(Ok(row))
}
}
pub enum Output {
File(String),
Stdout,
Stderr,
}
pub trait IntoOutput {
fn into_output(self) -> Output;
}
impl IntoOutput for Output {
fn into_output(self) -> Output {
self
}
}
Some(row)
impl IntoOutput for String {
fn into_output(self) -> Output {
Output::File(self)
}
}
impl IntoOutput for &str {
fn into_output(self) -> Output {
Output::File(String::from(self))
}
}
impl XlsxReader {
pub fn to_csv(&self) -> XlsxToCsvLines<'_> {
pub fn to_csv_lines(mut self) -> Result<XlsxToCsvLines, Error> {
self.finish()?;
let num_rows = self.get_worksheet_dimensions().1;
XlsxToCsvLines {
let end_of_line = self.args.end_of_line.clone();
let separator = String::from(self.args.separator);
Ok(XlsxToCsvLines {
xlsx_reader: self,
current_row: 0,
num_rows,
separator,
end_of_line,
})
}
pub fn to_csv(self, output: impl IntoOutput) -> Result<(), Error> {
let output = output.into_output();
let mut writer: Box<dyn Write> = match output {
Output::File(filename) => Box::new(BufWriter::new(File::open(filename)?)),
Output::Stdout => Box::new(BufWriter::new(stdout().lock())),
Output::Stderr => Box::new(BufWriter::new(stderr().lock())),
};
for line in self.to_csv_lines()? {
writer.write_all(line?.as_bytes())?;
}
Ok(())
}
}

Loading…
Cancel
Save