From d4a75ffb690aaf83ea2499b0f34a43c4bf5d511c Mon Sep 17 00:00:00 2001 From: Nicolas Sanchez Date: Sat, 4 Oct 2025 14:12:21 +0200 Subject: [PATCH] version foctionnelle --- .~lock.test_masque.xlsx# | 1 + src/arguments.rs | 23 +++++------ src/error.rs | 18 +++++++++ src/extractor.rs | 83 --------------------------------------- src/main.rs | 68 +++++++++++++++++++++++++++----- test_masque.csv | 4 ++ test_masque.xlsx | Bin 0 -> 5735 bytes 7 files changed, 92 insertions(+), 105 deletions(-) create mode 100644 .~lock.test_masque.xlsx# create mode 100644 src/error.rs delete mode 100644 src/extractor.rs create mode 100644 test_masque.csv create mode 100644 test_masque.xlsx diff --git a/.~lock.test_masque.xlsx# b/.~lock.test_masque.xlsx# new file mode 100644 index 0000000..fa82ba9 --- /dev/null +++ b/.~lock.test_masque.xlsx# @@ -0,0 +1 @@ +,sanchezn,pc-sanchezn,04.10.2025 13:10,file:///home/sanchezn/.config/libreoffice/4; \ No newline at end of file diff --git a/src/arguments.rs b/src/arguments.rs index 38417f6..776100d 100644 --- a/src/arguments.rs +++ b/src/arguments.rs @@ -2,19 +2,16 @@ use clap::Parser; #[derive(Parser, Debug)] pub struct Arguments { - /// path to the xlsx file + /// Path to the xlsx file #[arg()] pub file: String, - /// path to the output csv file + /// Separator + #[arg(short, long, default_value_t = ';')] + pub separator: char, + /// Replacement char to replace separator in cells text #[arg(short, long)] - pub output: Option, - /// worksheets to convert to xlsx (numbers, or names, or nothing to convert all worksheets) - #[arg(short, long)] - pub worksheets: Vec, - /// separator char. If many defined, use the first that is not used in cells. - #[arg(short, long, value_delimiter = ',', default_values_t = [';'])] - pub separator: Vec, - /// char to replace separator char in cells. If no replacement, error will be fired - #[arg(short, long)] - pub replacement: Option, -} \ No newline at end of file + pub replacement: Option, + /// Default hidden lines are not included to output + #[arg(short, long, default_value_t=false)] + pub include_hidden_lines: bool, +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..690ed11 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,18 @@ +use std::fmt; + +#[derive(Debug, Clone)] +pub struct Error { + pub msg: String +} + +impl Error { + pub fn new(msg: &str) -> Self { + Error { msg: String::from(msg)} + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Error: {}", self.msg) + } +} \ No newline at end of file diff --git a/src/extractor.rs b/src/extractor.rs deleted file mode 100644 index 5bfac11..0000000 --- a/src/extractor.rs +++ /dev/null @@ -1,83 +0,0 @@ -use umya_spreadsheet::{Spreadsheet, Worksheet}; - -#[derive(Debug)] -pub struct Extractor<'a> { - book: Spreadsheet, - sheet: Option<&'a Worksheet>, - pub separator: char, - pub replacement: Option, - pub merge_fill: MergeFill, - pub exclude_hidden: bool, -} - -impl<'a> Extractor<'a> { - pub fn new(book: Spreadsheet) -> Self { - Extractor { - book, - sheet: None, - separator: ';', - replacement: None, - merge_fill: MergeFill::None, - exclude_hidden: true, - } - } - - pub fn new_with_options( - book: Spreadsheet, - separator: char, - replacement: Option, - ) -> Self { - Extractor { - book, - sheet: None, - separator, - replacement, - merge_fill: MergeFill::None, - exclude_hidden: true, - } - } - - fn _is_row_hidden(&self, row_index: u32) -> Option { - if let Some(row) = self.sheet.unwrap().get_row_dimension(&row_index) { - if *row.get_hidden() { - return Some(false); - } else { - return Some(true); - } - } - None - } - - fn _is_column_hidden(&self, column_index: u32) -> Option { - if let Some(column) = self.sheet.unwrap().get_column_dimension_by_number(&column_index) { - if *column.get_hidden() { - return Some(false); - } else { - return Some(true); - } - } - None - } - - fn _is_cell_in_merge(&self, row_index: u32, column_index: u32) -> bool { - let merges = self.sheet.unwrap().get_merge_cells(); - for merge in merges { - if row_index >= *merge.get_coordinate_start_row().unwrap().get_num() - && row_index <= *merge.get_coordinate_end_row().unwrap().get_num() - && column_index >= *merge.get_coordinate_start_col().unwrap().get_num() - && column_index <= *merge.get_coordinate_end_col().unwrap().get_num() - { - return true; - } - } - false - } -} - -#[derive(Debug)] -pub enum MergeFill { - None, - Horizontal, - Vertical, - Both, -} diff --git a/src/main.rs b/src/main.rs index 79411ed..34f74e9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,67 @@ -use std::path::Path; use clap::Parser; +use std::path::Path; use umya_spreadsheet::reader; -pub mod extractor; -use extractor::Extractor; - pub mod arguments; use arguments::Arguments; -fn main() { - let _args = Arguments::parse(); +pub mod error; +use crate::error::Error; - let book = reader::xlsx::read(Path::new("anafi.xlsx")).unwrap(); - let _extractor = Extractor::new(book); -} +fn main() -> Result<(), Error> { + let args = Arguments::parse(); + let book = reader::xlsx::read(Path::new(&args.file)) + .expect(format!("Can't open {}", args.file).as_str()); + + let sheet = match book.get_sheet(&0) { + Some(sheet) => sheet, + None => return Err(Error::new("cannot open sheet")), + }; + let (num_cols, num_rows) = sheet.get_highest_column_and_row(); + + for i in 1..=num_rows { + if ! args.include_hidden_lines { + match sheet.get_row_dimension(&i) { + Some(dim) => { + if *dim.get_hidden() { + continue; + } + } + None => continue, + } + } + let row = sheet.get_collection_by_row(&i); + let row_len = row.len(); + let mut first = true; + for cell in row { + if first { + first = false; + } else { + print!("{}", args.separator); + } + + let mut value = cell.get_formatted_value(); + if let Some(ref replacement) = args.replacement { + value = value.replace(args.separator, replacement); + } else { + if value.contains(args.separator) { + return Err(Error::new( + format!( + "Cell {} contains separator char", + cell.get_coordinate().get_coordinate() + ) + .as_str(), + )); + } + } + print!("{}", value); + } + for _ in row_len..num_cols as usize { + print!("{}", args.separator); + } + println!(""); + } + + Ok(()) +} diff --git a/test_masque.csv b/test_masque.csv new file mode 100644 index 0000000..bcd028a --- /dev/null +++ b/test_masque.csv @@ -0,0 +1,4 @@ +A1;12;10 +A2;33; +A4,A4;45; +A5;90; diff --git a/test_masque.xlsx b/test_masque.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5f6bfa706a8ca8f35ad25b3e108755ebc4072fd6 GIT binary patch literal 5735 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 U!nv#n2FCTv;|Y4E@K@IV0OU2VE&u=k literal 0 HcmV?d00001