Fix ingredient parsing to be less obnoxious
This commit is contained in:
parent
7025ee9e3a
commit
63860cd05a
|
@ -131,10 +131,7 @@ fn prepare_grocery_list(ingredients: &Vec<(Ingredient, Vec<String>)>) -> Result<
|
||||||
)?;
|
)?;
|
||||||
writeln!(out)?; // leave an empty line
|
writeln!(out)?; // leave an empty line
|
||||||
for (ingredient, recipes) in ingredients {
|
for (ingredient, recipes) in ingredients {
|
||||||
writeln!(out, "- [ ] {}", ingredient)?;
|
writeln!(out, "- [ ] {} ({})", ingredient, recipes.join(", "))?;
|
||||||
for recipe in recipes {
|
|
||||||
writeln!(out, " * {}", recipe)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
|
|
|
@ -159,7 +159,7 @@ impl<'de> serde::de::Visitor<'de> for IngredientVisitor {
|
||||||
where
|
where
|
||||||
E: serde::de::Error,
|
E: serde::de::Error,
|
||||||
{
|
{
|
||||||
use std::cmp::min;
|
use std::cmp::{max, min};
|
||||||
|
|
||||||
let quantity_regex_start: regex::Regex =
|
let quantity_regex_start: regex::Regex =
|
||||||
regex::Regex::new(r"^(?P<v>[0-9,\.]+)\s*(?P<u>\w+)?\s+(?P<i>.*)").unwrap();
|
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)
|
.captures(value)
|
||||||
.or_else(|| quantity_regex_end.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 um = captures.name("u");
|
||||||
let u = um.map(|u| u.as_str()).unwrap_or("");
|
let u = um.map(|u| u.as_str()).unwrap_or("");
|
||||||
let im = captures.name("i").unwrap();
|
let im = captures.name("i").unwrap();
|
||||||
let i = im.as_str();
|
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 {
|
let name = match unit {
|
||||||
Unit::None => {
|
Unit::None => {
|
||||||
// pick the longest string including what was recognized by the regex as the possible unit
|
// pick the longest string including what was recognized by the regex as the possible unit
|
||||||
let start = um
|
let range = um
|
||||||
.map(|um| min(um.start(), im.start()))
|
.map(|um| min(um.start(), im.start())..max(um.end(), im.end()))
|
||||||
.unwrap_or_else(|| im.start());
|
.unwrap_or_else(|| im.start()..im.end());
|
||||||
&value[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,
|
_ => i,
|
||||||
}
|
}
|
||||||
|
@ -218,7 +224,7 @@ impl IngredientVisitor {
|
||||||
v = v / 1000.0;
|
v = v / 1000.0;
|
||||||
Unit::Kilogram
|
Unit::Kilogram
|
||||||
}
|
}
|
||||||
"hg" => {
|
"hg" | "etto" | "etti" => {
|
||||||
v = v / 10.0;
|
v = v / 10.0;
|
||||||
Unit::Kilogram
|
Unit::Kilogram
|
||||||
}
|
}
|
||||||
|
@ -231,15 +237,15 @@ impl IngredientVisitor {
|
||||||
v = v / 100.0;
|
v = v / 100.0;
|
||||||
Unit::Liter
|
Unit::Liter
|
||||||
}
|
}
|
||||||
"ml" => {
|
"ml" | "cc" => {
|
||||||
v = v / 1000.0;
|
v = v / 1000.0;
|
||||||
Unit::Liter
|
Unit::Liter
|
||||||
}
|
}
|
||||||
"tl" => {
|
"tl" | "cucchiaino" | "cucchiaini" => {
|
||||||
v = v / 1000.0 * 5.0;
|
v = v / 1000.0 * 5.0;
|
||||||
Unit::Liter
|
Unit::Liter
|
||||||
}
|
}
|
||||||
"el" => {
|
"el" | "cucchiaio" | "cucchiai" => {
|
||||||
v = v / 1000.0 * 15.0;
|
v = v / 1000.0 * 15.0;
|
||||||
Unit::Liter
|
Unit::Liter
|
||||||
}
|
}
|
||||||
|
@ -260,12 +266,19 @@ impl IngredientVisitor {
|
||||||
|
|
||||||
impl core::fmt::Display for Ingredient {
|
impl core::fmt::Display for Ingredient {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{amount:.3}{unit} {name}",
|
"{amount}{pad}{unit} {name}",
|
||||||
name = self.name,
|
name = self.name,
|
||||||
amount = self.amount,
|
amount = (self.amount * ROUNDING_EXP).round() / ROUNDING_EXP,
|
||||||
unit = self.unit
|
pad = match self.unit {
|
||||||
|
Unit::None => "",
|
||||||
|
_ => " ",
|
||||||
|
},
|
||||||
|
unit = self.unit,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue