Fix ingredient parsing to be less obnoxious

This commit is contained in:
Matteo Settenvini 2022-08-12 23:36:27 +02:00
parent 7025ee9e3a
commit 63860cd05a
Signed by: matteo
GPG Key ID: 8576CC1AD97D42DF
2 changed files with 28 additions and 18 deletions

View File

@ -131,10 +131,7 @@ fn prepare_grocery_list(ingredients: &Vec<(Ingredient, Vec<String>)>) -> Result<
)?;
writeln!(out)?; // leave an empty line
for (ingredient, recipes) in ingredients {
writeln!(out, "- [ ] {}", ingredient)?;
for recipe in recipes {
writeln!(out, " * {}", recipe)?;
}
writeln!(out, "- [ ] {} ({})", ingredient, recipes.join(", "))?;
}
Ok(out)

View File

@ -159,7 +159,7 @@ impl<'de> serde::de::Visitor<'de> for IngredientVisitor {
where
E: serde::de::Error,
{
use std::cmp::min;
use std::cmp::{max, min};
let quantity_regex_start: regex::Regex =
regex::Regex::new(r"^(?P<v>[0-9,\.]+)\s*(?P<u>\w+)?\s+(?P<i>.*)").unwrap();
@ -170,20 +170,26 @@ impl<'de> serde::de::Visitor<'de> for IngredientVisitor {
.captures(value)
.or_else(|| quantity_regex_end.captures(value))
{
let v = captures.name("v").unwrap().as_str();
let vm = captures.name("v").unwrap();
let v = vm.as_str();
let um = captures.name("u");
let u = um.map(|u| u.as_str()).unwrap_or("");
let im = captures.name("i").unwrap();
let i = im.as_str();
let (amount, unit) = Self::parse_quantity(v, u)?;
let (mut amount, unit) = Self::parse_quantity(v, u)?;
let name = match unit {
Unit::None => {
// pick the longest string including what was recognized by the regex as the possible unit
let start = um
.map(|um| min(um.start(), im.start()))
.unwrap_or_else(|| im.start());
&value[start..im.end()]
let range = um
.map(|um| min(um.start(), im.start())..max(um.end(), im.end()))
.unwrap_or_else(|| im.start()..im.end());
if range.start <= vm.start() && range.end >= vm.end() {
amount = 1.0; // e.g. for "Parsley, 5 leaves" -> Ingredient { 1, no unit, 'Parsley, 5 leaves' }
}
&value[range]
}
_ => i,
}
@ -218,7 +224,7 @@ impl IngredientVisitor {
v = v / 1000.0;
Unit::Kilogram
}
"hg" => {
"hg" | "etto" | "etti" => {
v = v / 10.0;
Unit::Kilogram
}
@ -231,15 +237,15 @@ impl IngredientVisitor {
v = v / 100.0;
Unit::Liter
}
"ml" => {
"ml" | "cc" => {
v = v / 1000.0;
Unit::Liter
}
"tl" => {
"tl" | "cucchiaino" | "cucchiaini" => {
v = v / 1000.0 * 5.0;
Unit::Liter
}
"el" => {
"el" | "cucchiaio" | "cucchiai" => {
v = v / 1000.0 * 15.0;
Unit::Liter
}
@ -260,12 +266,19 @@ impl IngredientVisitor {
impl core::fmt::Display for Ingredient {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
const PRECISION: u32 = 3;
const ROUNDING_EXP: f64 = 10isize.pow(PRECISION) as f64;
write!(
f,
"{amount:.3}{unit} {name}",
"{amount}{pad}{unit} {name}",
name = self.name,
amount = self.amount,
unit = self.unit
amount = (self.amount * ROUNDING_EXP).round() / ROUNDING_EXP,
pad = match self.unit {
Unit::None => "",
_ => " ",
},
unit = self.unit,
)
}
}