""" Tamil Rule-Based Lemmatizer Converts inflected Tamil word forms back to their root/base form. Strategy: 1. Sandhi reversal — handles gemination changes that happen when case suffixes attach (e.g. நாடு + தின் → நாட்டின் → நாடு) 2. Plain suffix stripping — removes case/number markers that attach without phonological change (e.g. கட்சிகள் → கட்சி) Rules are ordered longest-first within each table so the most specific pattern always wins. """ # --------------------------------------------------------------------------- # TABLE 1: SANDHI REVERSAL # Handles cases where the stem itself changes phonologically before the suffix. # --------------------------------------------------------------------------- _SANDHI_MAP = [ # -ம் nouns pluralised: stem-final ம் → ங்க before கள் ("ங்களின்", "ம்"), ("ங்களில்", "ம்"), ("ங்களை", "ம்"), ("ங்களுக்கு", "ம்"), ("ங்கள்", "ம்"), # -டு nouns (நாடு, பாடு, …) ("ட்டின்", "டு"), ("ட்டில்", "டு"), ("ட்டை", "டு"), ("ட்டோடு", "டு"), # -ண்டு nouns ("ண்டின்", "ண்டு"), ("ண்டில்", "ண்டு"), # -ம் nouns with direct case (சட்டமன்றம் → த்த + case) ("த்தின்", "ம்"), ("த்தில்", "ம்"), ("த்தை", "ம்"), # -று nouns ("ற்றில்", "று"), ("ற்றின்", "று"), # -கு nouns ("க்கில்", "கு"), ("க்கின்", "கு"), # -பு nouns ("ப்பில்", "பு"), ("ப்பின்", "பு"), # -ல் nouns ("ல்லில்", "ல்"), ("ல்லின்", "ல்"), # -ர் agent nouns, pluralised ("ர்களை", "ர்"), ("ர்களின்", "ர்"), ("ர்களில்", "ர்"), ("ர்கள்", "ர்"), ] # --------------------------------------------------------------------------- # TABLE 2: PLAIN SUFFIX STRIPPING # No stem change; just remove the suffix (and optionally append a replacement). # --------------------------------------------------------------------------- _SUFFIX_MAP = [ # Verbal nouns ending in -த்து with possessive plural ("த்துக்களின்", "த்து"), ("த்துக்களை", "த்து"), ("த்துக்கள்", "த்து"), # கள் + case markers — strip only the case marker, keep கள் # (மக்கள் is itself a root; stripping கள் would be wrong) ("களுக்கு", "கள்"), ("களிடம்", "கள்"), ("களோடு", "கள்"), ("களால்", "கள்"), # Plain கள் plurals — strip entirely (root has no கள்) ("களின்", ""), ("களில்", ""), ("களை", ""), ("கள்", ""), # -ய் / -யு stems with case ("யின்", ""), ("யில்", ""), ("யை", ""), ("யோடு", ""), # -வு stems ("விற்கு", "வு"), ("வின்", "வு"), ("வில்", "வு"), ("வை", "வு"), # Role suffixes (-ராக → -ர்) ("ராகவே", "ர்"), ("ராக", "ர்"), ("வராக", "வர்"), # General oblique / case suffixes ("ஆக", ""), ("இன்", ""), ("இல்", ""), ("க்கு", ""), ("டன்", ""), ("உடன்", ""), ("ஓடு", ""), ("ஆல்", ""), ("இருந்து", ""), ("க்காக", ""), ("உக்கு", ""), ] # Minimum character length to accept a stripped root as valid _MIN_ROOT_LEN = 2 def get_root(word: str) -> str: """ Return the root/base form of a Tamil word. Examples -------- >>> get_root("சட்டமன்றத்தில்") 'சட்டமன்றம்' >>> get_root("கட்சிகள்") 'கட்சி' >>> get_root("சென்னை") 'சென்னை' # proper noun with no suffix — returned unchanged """ word = word.strip() # Step 1: sandhi reversal for suffix, replacement in _SANDHI_MAP: if word.endswith(suffix): root = word[: -len(suffix)] + replacement if len(root) >= _MIN_ROOT_LEN: return root # Step 2: plain suffix stripping for suffix, replacement in _SUFFIX_MAP: if word.endswith(suffix): root = word[: -len(suffix)] + replacement if len(root) >= _MIN_ROOT_LEN: return root return word def get_root_with_surface(surface_word: str) -> tuple[str, str]: """ Return (root, surface_word). Convenience wrapper so callers can keep both forms easily. """ return get_root(surface_word), surface_word