From 059636b7bda214e6ea6d77d06a66129fcd2c593d Mon Sep 17 00:00:00 2001 From: satsragclaw <270253513+satsragclaw@users.noreply.github.com> Date: Tue, 14 Jul 2026 22:35:22 +0800 Subject: [PATCH] Fix normalize_text handling of Nirugu and ZWJ --- mongol_norm/shaper.py | 21 ++++++++++++++------- tests/test_joiners.py | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/mongol_norm/shaper.py b/mongol_norm/shaper.py index 0e0e21b..4efb196 100644 --- a/mongol_norm/shaper.py +++ b/mongol_norm/shaper.py @@ -84,6 +84,18 @@ def is_mongolian_letter(cp): return cp in MONGOLIAN_BLOCK +def is_mongolian_word_char(cp): + """Return whether *cp* participates in a Mongolian word run. + + Strict word validation and mixed-text segmentation must share this + classification. Splitting at Nirugu or ZWJ changes neighbouring letters' + isol/init/medi/fina positions and therefore changes normalization. + """ + return (is_mongolian_letter(cp) + or cp in FVS_CPS + or cp in (MVS_CP, NNBSP_CP, NIRUGU_CP, ZWJ_CP)) + + def _check_word_chars(text): """ Raise ValueError if `text` contains any char that is not a Mongolian @@ -97,12 +109,7 @@ def _check_word_chars(text): """ for i, ch in enumerate(text): cp = ord(ch) - if (is_mongolian_letter(cp) - or cp in FVS_CPS - or cp == MVS_CP - or cp == NNBSP_CP - or cp == NIRUGU_CP - or cp == ZWJ_CP): + if is_mongolian_word_char(cp): continue # Build a helpful error with the offending char's position and id. # 报错信息含越位字符的位置和码位。 @@ -1376,7 +1383,7 @@ def normalize_text(self, text): for i, ch in enumerate(text): cp = ord(ch) - is_mong = is_mongolian_letter(cp) or cp in FVS_CPS or cp == MVS_CP or cp == NNBSP_CP + is_mong = is_mongolian_word_char(cp) if current_is_mong is None: current_is_mong = is_mong elif is_mong != current_is_mong: diff --git a/tests/test_joiners.py b/tests/test_joiners.py index 771cfec..e3a1898 100644 --- a/tests/test_joiners.py +++ b/tests/test_joiners.py @@ -84,5 +84,20 @@ def test_single_sided_nirugu_round_trips(self): self._round_trips(text) +class TestJoinerNormalizeText(_Base): + def test_nirugu_word_uses_the_same_joining_context_as_normalize(self): + word = NIRUGU + U + NIRUGU + self.assertEqual(self.s.normalize_text(word), self.s.normalize(word)) + + def test_nirugu_word_inside_mixed_text_uses_the_same_joining_context(self): + word = NIRUGU + U + NIRUGU + self.assertEqual(self.s.normalize_text('A ' + word + ' B'), + 'A ' + self.s.normalize(word) + ' B') + + def test_zwj_word_uses_the_same_joining_context_as_normalize(self): + word = ZWJ + D + self.assertEqual(self.s.normalize_text(word), self.s.normalize(word)) + + if __name__ == '__main__': unittest.main() \ No newline at end of file