diff --git a/app/src/main/java/de/lukasneugebauer/nextcloudcookbook/recipe/data/YieldCalculatorImpl.kt b/app/src/main/java/de/lukasneugebauer/nextcloudcookbook/recipe/data/YieldCalculatorImpl.kt index 57ecedd1..2e561e91 100644 --- a/app/src/main/java/de/lukasneugebauer/nextcloudcookbook/recipe/data/YieldCalculatorImpl.kt +++ b/app/src/main/java/de/lukasneugebauer/nextcloudcookbook/recipe/data/YieldCalculatorImpl.kt @@ -1,6 +1,7 @@ package de.lukasneugebauer.nextcloudcookbook.recipe.data import de.lukasneugebauer.nextcloudcookbook.recipe.domain.YieldCalculator +import java.text.Normalizer import java.text.NumberFormat import java.util.Locale @@ -33,20 +34,62 @@ class YieldCalculatorImpl(customLocale: Locale? = null) : YieldCalculator { if (originalYield < 1) return@map ingredient + // Fraction val matchResult = FRACTION_REGEX.matchEntire(ingredient) if (matchResult !== null) { val (fractionMatch, wholeNumberPartRaw, numeratorRaw, denominatorRaw) = matchResult.destructured val wholeNumberPart = wholeNumberPartRaw.toDoubleOrNull() ?: 0.0 - val numerator = numeratorRaw.toDouble() - val denominator = denominatorRaw.toDouble() + val numerator: Double + val denominator: Double + + // Unicode fraction + if (numeratorRaw.isBlank()) { + val normalizedFraction = Normalizer.normalize(fractionMatch, Normalizer.Form.NFKD) + val (numeratorPart, denominatorPart) = + normalizedFraction + .split("\u2044") + .map { it.toDouble() } + + numerator = numeratorPart + denominator = denominatorPart + } else { + numerator = numeratorRaw.toDouble() + denominator = denominatorRaw.toDouble() + } val decimalAmount = wholeNumberPart + numerator / denominator val newAmount = (decimalAmount / originalYield) * currentYield + val newWholeNumberPart = newAmount.toInt() + var newNumerator = (newAmount - newWholeNumberPart) * 16 + val newAmountString: String + + if (newNumerator % 1 == 0.0) { + fun gcd( + a: Int, + b: Int, + ): Int = if (b == 0) a else gcd(b, a % b) + val div = gcd(newNumerator.toInt(), 16) + newNumerator /= div + val newDenominator = 16 / div + val prefix = if (newWholeNumberPart != 0) "$newWholeNumberPart" else "" + + newAmountString = + if (newNumerator == 0.0) { + prefix + } else if (prefix.isBlank()) { + "${newNumerator.toInt()}/$newDenominator" + } else { + "$prefix ${newNumerator.toInt()}/$newDenominator" + } + } else { + newAmountString = numberFormat.format(newAmount).toString() + } - return@map ingredient.replace(fractionMatch, numberFormat.format(newAmount)) + return@map ingredient.replace(fractionMatch, newAmountString) } + // Decimal if (isValidIngredientSyntax(ingredient)) { val possibleUnit = ingredient.split(" ") @@ -76,7 +119,7 @@ class YieldCalculatorImpl(customLocale: Locale? = null) : YieldCalculator { companion object { const val DOUBLE_HASH_PREFIX = "## " val MULTIPLE_SEPARATORS_REGEX = Regex("""^-?\d+(?:[.,]\d+){2,}.*""") - val FRACTION_REGEX = Regex("""^((\d+\s+)?(\d+)\s*/\s*(\d+)).*""") - val SYNTAX_REGEX = Regex("""^\d+(?:\.\d+)?(?:/\d+)?\s?.*$""") + val FRACTION_REGEX = Regex("""^((\d+\s+)?(?:\p{No}|(\d+)\s*\/\s*(\d+))).*""") + val SYNTAX_REGEX = Regex("""^(?:(?:\d+\s)?(?:\d+\/\d+|\p{No})|\d+(?:\.\d+)?)[a-zA-z]*\s.*$""") } } diff --git a/app/src/test/java/de/lukasneugebauer/nextcloudcookbook/YieldCalculatorRecalculateIngredientsUnitTest.kt b/app/src/test/java/de/lukasneugebauer/nextcloudcookbook/YieldCalculatorRecalculateIngredientsUnitTest.kt index f8983dcd..5c556710 100644 --- a/app/src/test/java/de/lukasneugebauer/nextcloudcookbook/YieldCalculatorRecalculateIngredientsUnitTest.kt +++ b/app/src/test/java/de/lukasneugebauer/nextcloudcookbook/YieldCalculatorRecalculateIngredientsUnitTest.kt @@ -20,7 +20,6 @@ class YieldCalculatorRecalculateIngredientsUnitTest { "3 1/4 tsp salt", "5 bell pepper", "1.5 potatoes", - "1,6 carrots", ) ingredients.forEach { assertTrue(yieldCalculator.isValidIngredientSyntax(it)) @@ -36,6 +35,8 @@ class YieldCalculatorRecalculateIngredientsUnitTest { "some oregano", "1.500,5 g mushrooms", "1,250.50 g beans", + "1,6 carrots", + "2-3 bananas", ) ingredients.forEach { assertFalse(yieldCalculator.isValidIngredientSyntax(it)) @@ -60,6 +61,10 @@ class YieldCalculatorRecalculateIngredientsUnitTest { "1 - 2 onions", "2-3 bananas", "1 150 g apples", + "ΒΌ unicode", + "3/8 cup creme", + "3/5 bananas", + "0.25 cup yogurt", ) val expectedIngredients = listOf( @@ -67,20 +72,24 @@ class YieldCalculatorRecalculateIngredientsUnitTest { "6tbsp oil", "1 cup sugar", "3 kg butter", - "6.5 tsp salt", + "6 1/2 tsp salt", "10 bell pepper", "pepper", "some oregano", "3 potatoes", - "3.2 carrots", + "1,6 carrots", "2 - 2 onions", - "4 bananas", + "2-3 bananas", "2 150 g apples", + "1/2 unicode", + "3/4 cup creme", + "1.2 bananas", + "0.5 cup yogurt", ) assertEquals( - yieldCalculator.recalculateIngredients(ingredients, 2, 1), expectedIngredients, + yieldCalculator.recalculateIngredients(ingredients, 2, 1), ) } }