FIX: Cast to string now checks for dates, currencies or percentages

Fixes part of #535
This commit is contained in:
Nicolás Hatcher
2025-11-16 17:17:35 +01:00
committed by Nicolás Hatcher Andrés
parent 7e966baa0d
commit 5ff4774c5a
4 changed files with 48 additions and 12 deletions

View File

@@ -5,6 +5,7 @@ use crate::{
token::Error, token::Error,
types::CellReferenceIndex, types::CellReferenceIndex,
}, },
formatter::format::parse_formatted_number,
model::Model, model::Model,
}; };
@@ -89,20 +90,31 @@ impl Model {
self.cast_to_number(result, cell) self.cast_to_number(result, cell)
} }
fn cast_to_number( pub(crate) fn cast_to_number(
&mut self, &mut self,
result: CalcResult, result: CalcResult,
cell: CellReferenceIndex, cell: CellReferenceIndex,
) -> Result<f64, CalcResult> { ) -> Result<f64, CalcResult> {
match result { match result {
CalcResult::Number(f) => Ok(f), CalcResult::Number(f) => Ok(f),
CalcResult::String(s) => match s.parse::<f64>() { CalcResult::String(s) => match s.trim().parse::<f64>() {
Ok(f) => Ok(f), Ok(f) => Ok(f),
_ => Err(CalcResult::new_error( _ => {
let mut currencies = vec!["$", ""];
let currency = &self.locale.currency.symbol;
if !currencies.iter().any(|e| e == currency) {
currencies.push(currency);
}
// We try to parse as number
if let Ok((v, _number_format)) = parse_formatted_number(&s, &currencies) {
return Ok(v);
}
Err(CalcResult::new_error(
Error::VALUE, Error::VALUE,
cell, cell,
"Expecting number".to_string(), "Expecting number".to_string(),
)), ))
}
}, },
CalcResult::Boolean(f) => { CalcResult::Boolean(f) => {
if f { if f {

View File

@@ -744,10 +744,10 @@ fn parse_date(value: &str) -> Result<(i32, String), String> {
/// "30.34%" => (0.3034, "0.00%") /// "30.34%" => (0.3034, "0.00%")
/// 100€ => (100, "100€") /// 100€ => (100, "100€")
pub(crate) fn parse_formatted_number( pub(crate) fn parse_formatted_number(
value: &str, original: &str,
currencies: &[&str], currencies: &[&str],
) -> Result<(f64, Option<String>), String> { ) -> Result<(f64, Option<String>), String> {
let value = value.trim(); let value = original.trim();
let scientific_format = "0.00E+00"; let scientific_format = "0.00E+00";
// Check if it is a percentage // Check if it is a percentage
@@ -799,7 +799,8 @@ pub(crate) fn parse_formatted_number(
} }
} }
if let Ok((serial_number, format)) = parse_date(value) { // check if it is a date. NOTE: we don't trim the original here
if let Ok((serial_number, format)) = parse_date(original) {
return Ok((serial_number as f64, Some(format))); return Ok((serial_number as f64, Some(format)));
} }

View File

@@ -1163,11 +1163,34 @@ impl Model {
if args.len() != 2 { if args.len() != 2 {
return CalcResult::new_args_number_error(cell); return CalcResult::new_args_number_error(cell);
} }
let value = match self.get_number(&args[0], cell) {
let value = self.evaluate_node_in_context(&args[0], cell);
let multiple = self.evaluate_node_in_context(&args[1], cell);
// if both are empty => #N/A
if matches!(value, CalcResult::EmptyArg) || matches!(multiple, CalcResult::EmptyArg) {
return CalcResult::Error {
error: Error::NA,
origin: cell,
message: "Bad argument for MROUND".to_string(),
};
}
// Booleans are not cast
if matches!(value, CalcResult::Boolean(_)) {
return CalcResult::new_error(Error::VALUE, cell, "Expecting number".to_string());
}
if matches!(multiple, CalcResult::Boolean(_)) {
return CalcResult::new_error(Error::VALUE, cell, "Expecting number".to_string());
}
let value = match self.cast_to_number(value, cell) {
Ok(f) => f, Ok(f) => f,
Err(s) => return s, Err(s) => return s,
}; };
let multiple = match self.get_number(&args[1], cell) { let multiple = match self.cast_to_number(multiple, cell) {
Ok(f) => f, Ok(f) => f,
Err(s) => return s, Err(s) => return s,
}; };

Binary file not shown.