From 472d4b5b366f0dc874041a78fc7c2ff1b982f8be Mon Sep 17 00:00:00 2001 From: Ahmet Selim FEDAKAR <122402435+selimfedakar@users.noreply.github.com> Date: Fri, 13 Nov 2026 10:32:50 +0300 Subject: [PATCH] fix: keep unit 'one' after a Swedish hundreds-block before a multiplier _parse_0_99 returns None for a standalone 'en'/'ett', so a hundreds-block with unit-one remainder returned early and the following 'tusen' never attached: 'hundra ett tusen' normalized to '100 1000' instead of '101000'. Add _parse_0_99_after_hundred (mirroring the Danish sibling, which is reference-correct) to accept 'en'/'ett' as unit 1 only in the unambiguous hundreds-remainder position. Adds a focused test. --- .../languages/swedish/number_normalizer.py | 21 +++++++++++++++++-- .../swedish_number_normalizer_test.py | 18 ++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/normalization/languages/swedish/number_normalizer.py b/normalization/languages/swedish/number_normalizer.py index c145e79..83abe51 100644 --- a/normalization/languages/swedish/number_normalizer.py +++ b/normalization/languages/swedish/number_normalizer.py @@ -322,7 +322,7 @@ def _parse_0_999(self, words: list[str], i: int, n: int) -> tuple[int, int] | No return i + 1, 0 if _fold(words[i]) == "hundra": - tail = self._parse_0_99(words, i + 1, n) + tail = self._parse_0_99_after_hundred(words, i + 1, n) if tail is not None: je, tv = tail return je, 100 + tv @@ -334,7 +334,7 @@ def _parse_0_999(self, words: list[str], i: int, n: int) -> tuple[int, int] | No return None base = m * 100 j = i + 2 - tail = self._parse_0_99(words, j, n) + tail = self._parse_0_99_after_hundred(words, j, n) if tail is not None: je, tv = tail return je, base + tv @@ -342,6 +342,23 @@ def _parse_0_999(self, words: list[str], i: int, n: int) -> tuple[int, int] | No return self._parse_0_99(words, i, n) + def _parse_0_99_after_hundred( + self, words: list[str], i: int, n: int + ) -> tuple[int, int] | None: + """Parse 0–99, additionally accepting standalone ``en``/``ett`` as 1. + + A bare ``en``/``ett`` is ambiguous with the article elsewhere, so + ``_parse_0_99`` leaves it as a word. After a hundreds block it can only + be the unit 1 (``hundra ett`` = 101, ``hundra ett tusen`` = 101000), so + it is safe to read here. + """ + result = self._parse_0_99(words, i, n) + if result is not None: + return result + if i < n and _fold(words[i]) in ("en", "ett"): + return i + 1, 1 + return None + def _continues_number(self, word: str) -> bool: fw = _fold(word) if fw == "hundra" or fw == "tusen": diff --git a/tests/unit/languages/swedish_number_normalizer_test.py b/tests/unit/languages/swedish_number_normalizer_test.py index b05477d..8edcc96 100644 --- a/tests/unit/languages/swedish_number_normalizer_test.py +++ b/tests/unit/languages/swedish_number_normalizer_test.py @@ -67,3 +67,21 @@ def test_kronor_word_not_treated_as_currency_suffix( normalizer: SwedishNumberNormalizer, ) -> None: assert normalizer("25 kronor") == "25 kronor" + + +@pytest.mark.parametrize( + ("text", "expected"), + [ + ("hundra ett", "101"), + ("två hundra en", "201"), + ("hundra ett tusen", "101000"), + ("två hundra ett tusen", "201000"), + ("tre hundra ett tusen fem", "301005"), + ], +) +def test_unit_one_after_hundred_keeps_grouping( + normalizer: SwedishNumberNormalizer, text: str, expected: str +) -> None: + """``en``/``ett`` as the ones part after a hundreds block is the unit 1, so + the thousands multiplier is not dropped (``hundra ett tusen`` = 101000).""" + assert normalizer(text) == expected