Skip to content

pol-Latn: greedy grapheme matching consumes the base letter of a decomposed diacritic — ⟨rż⟩/⟨rź⟩ mistranscribed via the ⟨rz⟩ digraph #255

Description

@jc0019

Summary

In Polish (pol-Latn), words containing the letter sequences ⟨rż⟩ or ⟨rź⟩ (where ⟨ż⟩/⟨ź⟩ are single letters, not part of a digraph) are transcribed incorrectly: the ⟨rz⟩ digraph rule consumes the ⟨r⟩ plus the base letter of the decomposed ⟨ż⟩/⟨ź⟩, deleting /r/ and leaving a stranded combining mark in the output.

Minimal reproduction

import epitran
epi = epitran.Epitran('pol-Latn')

epi.transliterate('skarżyć')     # 'skaʐ̇ɨt͡ɕ'   expected: 'skarʐɨt͡ɕ'
epi.transliterate('drży')        # 'dʐ̇ɨ'        expected: 'drʐɨ'
epi.transliterate('zmarźnięta')  # 'zmaʐ́ɲɛnta'  expected: 'zmarʑɲɛnta'

epi.trans_list('skarżyć')
# ['s', 'k', 'a', 'ʐ', '̇', 'ɨ', 't͡ɕ']   ← /r/ lost; stray U+0307 in output

The input encoding does not matter (NFC and NFD inputs both reproduce it). Environment: epitran 1.35.2, Python 3.11.

Root cause

Epitran.general_trans normalizes the input to NFD before matching (simple.py), so ⟨ż⟩ becomes z + U+0307. The greedy longest-match regex built by _build_greedy_match_regex then matches the digraph key rz against r + z, splitting the decomposed letter: the combining dot is orphaned and later emitted as an unmapped character, while ⟨rż⟩ = /rʐ/ surfaces as ⟨rz⟩ = /ʐ/.

The same failure class can in principle affect any language whose map contains a multigraph XY where Y is also the base letter of a decomposable letter in that orthography.

Proposed fix

Forbid a grapheme match from ending immediately before a combining mark, by appending a negative lookahead in _build_greedy_match_regex:

graphemes = sorted(g2p_keys, key=len, reverse=True)
pattern = f"({r'|'.join(graphemes)})"
# Don't split a base letter from its combining mark(s) — unless this map
# deliberately maps bare combining marks (e.g. tone diacritics).
if not any(unicodedata.combining(g[0]) for g in graphemes if g):
    pattern += r'(?!\p{M})'
return regex.compile(pattern, regex.I)

Tested on pol-Latn: skarżyćskarʐɨt͡ɕ, drżydrʐɨ, zmarźniętazmarʑɲɛnta, while regular ⟨rz⟩/⟨ż⟩ words (rzeka, żaba, może) are unchanged. The unicodedata.combining guard avoids regressing languages whose maps key bare combining marks directly.

Happy to submit a PR with this change plus regression tests if the approach looks right to you.

Context

Found while building a phonemicized Polish child-directed-speech lexicon for phonotactic-learning experiments; the bug affected 32 of ~44,000 word types (the skarżyć, drżeć, marznąć/zmarźnięty families).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions