Upload aztext/alphabet.py with huggingface_hub
Browse files- aztext/alphabet.py +66 -0
aztext/alphabet.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Canonical Azerbaijani (Latin script) alphabet constants and case helpers.
|
| 2 |
+
|
| 3 |
+
Modern North Azerbaijani (Republic of Azerbaijan) uses a 32-letter Latin
|
| 4 |
+
alphabet. Beyond ASCII it adds: ə Ə, ğ Ğ, ı I (dotless i), i İ (dotted i),
|
| 5 |
+
ö Ö, ş Ş, ç Ç, ü Ü.
|
| 6 |
+
|
| 7 |
+
The dotted/dotless ``i`` distinction is *semantically meaningful* and must
|
| 8 |
+
never be collapsed: i (U+0069) ≠ ı (U+0131) and İ (U+0130) ≠ I (U+0049).
|
| 9 |
+
|
| 10 |
+
Python's default ``str.lower``/``str.upper`` implement the *non-Turkic* rules
|
| 11 |
+
(``'i'.upper() == 'I'``), which is wrong for Azerbaijani. Use :func:`az_lower`
|
| 12 |
+
and :func:`az_upper` instead — they honour the Turkic i mappings:
|
| 13 |
+
|
| 14 |
+
upper('i') = 'İ' lower('I') = 'ı'
|
| 15 |
+
upper('ı') = 'I' lower('İ') = 'i'
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
# --- Vowels and consonants (lowercase) ---------------------------------------
|
| 19 |
+
# 9 vowels
|
| 20 |
+
AZ_VOWELS = "aeəıioöuü"
|
| 21 |
+
# 23 consonants (dotless/ordinary letters only; İ/I handled by the vowel i/ı)
|
| 22 |
+
AZ_CONSONANTS = "bcçdfgğhxjklmnpqrsştvyz"
|
| 23 |
+
|
| 24 |
+
# --- Full lowercase / uppercase alphabets (in canonical alphabet order) -------
|
| 25 |
+
# Alphabet order: a b c ç d e ə f g ğ h x ı i j k q l m n o ö p r s ş t u ü v y z
|
| 26 |
+
AZ_LOWER = "abcçdeəfgğhxıijkqlmnoöprsştuüvyz"
|
| 27 |
+
AZ_UPPER = "ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"
|
| 28 |
+
|
| 29 |
+
# All Azerbaijani letters (both cases), for membership tests / regex classes.
|
| 30 |
+
AZ_LETTERS = AZ_LOWER + AZ_UPPER
|
| 31 |
+
|
| 32 |
+
# --- Turkic-aware case mappings for the i-family -----------------------------
|
| 33 |
+
# These four characters are the ones Python gets wrong for Azerbaijani.
|
| 34 |
+
# i U+0069 LATIN SMALL LETTER I -> upper İ U+0130
|
| 35 |
+
# İ U+0130 LATIN CAPITAL LETTER I WITH DOT -> lower i U+0069
|
| 36 |
+
# ı U+0131 LATIN SMALL LETTER DOTLESS I -> upper I U+0049
|
| 37 |
+
# I U+0049 LATIN CAPITAL LETTER I -> lower ı U+0131
|
| 38 |
+
_UPPER_I_MAP = {"i": "İ", "ı": "I"}
|
| 39 |
+
_LOWER_I_MAP = {"İ": "i", "I": "ı"}
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def az_upper(text: str) -> str:
|
| 43 |
+
"""Uppercase ``text`` with correct Azerbaijani i-mapping.
|
| 44 |
+
|
| 45 |
+
``i`` -> ``İ`` and ``ı`` -> ``I`` are applied first so that the subsequent
|
| 46 |
+
plain ``str.upper()`` (which correctly handles ə→Ə, ç→Ç, ş→Ş, ğ→Ğ, ö→Ö,
|
| 47 |
+
ü→Ü, and all ASCII) never touches the dotted/dotless ``i`` incorrectly.
|
| 48 |
+
"""
|
| 49 |
+
text = text.replace("i", "İ").replace("ı", "I")
|
| 50 |
+
return text.upper()
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def az_lower(text: str) -> str:
|
| 54 |
+
"""Lowercase ``text`` with correct Azerbaijani i-mapping.
|
| 55 |
+
|
| 56 |
+
``İ`` -> ``i`` and ``I`` -> ``ı`` are applied first. This also avoids
|
| 57 |
+
Python's quirk where ``'İ'.lower()`` yields the two-character sequence
|
| 58 |
+
``'i' + COMBINING DOT ABOVE`` instead of a plain ``'i'``.
|
| 59 |
+
"""
|
| 60 |
+
text = text.replace("İ", "i").replace("I", "ı")
|
| 61 |
+
return text.lower()
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def is_az_letter(ch: str) -> bool:
|
| 65 |
+
"""True if ``ch`` is a single Azerbaijani alphabet letter."""
|
| 66 |
+
return len(ch) == 1 and ch in AZ_LETTERS
|