From a7126300ef2bb08d9be4eb5aefaa851dd39870d0 Mon Sep 17 00:00:00 2001 From: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com> Date: Thu, 30 Jul 2026 21:15:23 -0700 Subject: [PATCH] =?UTF-8?q?fix(transliterate):=20romanize=20royin=20words?= =?UTF-8?q?=20containing=20=E0=B8=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit romanize(..., engine="royin") raised IndexError on words containing ฤ (U+0E24), e.g. ฤดู, ฤก, ฤทธิ์. _romanize() built its consonant list with _RE_CONSONANT, which matches only thai_consonants and so excludes ฤ, while _replace_consonants() treats every key of _CONSONANTS - including ฤ - as a consonant and advances its index for each one. The two went out of sync and the index ran past the end of the list. The consonant list is now built with the same membership test the loop uses, so ฤ is romanized through its existing _CONSONANTS entry. Adds RU_TESTS and test_romanize_royin_ru to tests/core/test_transliterate.py. Closes #1444 --- pythainlp/transliterate/royin.py | 5 ++++- tests/core/test_transliterate.py | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/pythainlp/transliterate/royin.py b/pythainlp/transliterate/royin.py index 635be5096..cf6e15cdf 100644 --- a/pythainlp/transliterate/royin.py +++ b/pythainlp/transliterate/royin.py @@ -274,7 +274,10 @@ def _romanize(word: str) -> str: return "" word = _replace_vowels(_normalize(word)) - consonants = _RE_CONSONANT.findall(word) + # Use the same membership test as _replace_consonants(), which treats + # every key of _CONSONANTS as a consonant. _RE_CONSONANT only matches + # thai_consonants, so it misses ฤ and the two lists fall out of sync. + consonants = [c for c in word if c in _CONSONANTS] # 2-character word, all consonants if len(word) == 2 and len(consonants) == 2: diff --git a/tests/core/test_transliterate.py b/tests/core/test_transliterate.py index d66bf8e15..02ddf3059 100644 --- a/tests/core/test_transliterate.py +++ b/tests/core/test_transliterate.py @@ -38,6 +38,13 @@ "ชารินทร์": "charin", } +# words containing ฤ (U+0E24 THAI CHARACTER RU), see issue #1444 +RU_TESTS = { + "ฤก": "rueok", + "ฤดู": "rueadu", + "ฤทธิ์": "rueot", +} + # these are set of two-syllable words, # to test if the transliteration/romanization is consistent, say # romanize(1+2) = romanize(1) + romanize(2) @@ -60,6 +67,12 @@ def test_romanize_royin_basic(self): for word, expect in BASIC_TESTS.items(): self.assertEqual(romanize(word, engine="royin"), expect) # type: ignore[arg-type] + def test_romanize_royin_ru(self): + # ฤ (U+0E24) is a key of _CONSONANTS but is not in thai_consonants, + # so it used to desynchronise the consonant list and raise IndexError. + for word, expect in RU_TESTS.items(): + self.assertEqual(romanize(word, engine="royin"), expect) # type: ignore[arg-type] + def test_romanize_royin_consistency(self): for word, part1, part2 in CONSISTENCY_TESTS: self.assertEqual(