API output without Persian diacritics or written ezafe ی (company decision); tutor answers too
plain_persian() strips kasra/fatha/damma/shadda/sukun/hamza-above and the written «هی» ezafe, keeping tanwin. Applied at output, not in data: PlainPersianJSONRenderer runs one byte-level pass over every JSON response (~5 ms per MB locally), and to_plain() cleans tutor answers including the stream. Rewriting titles in the DB/seed would have broken question binding by title path and SeedRecord keys. Tests updated to expect the cleaned text; config/tests_plain_persian.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -133,3 +133,30 @@ def convert_figures(obj, _key=None):
|
||||
if isinstance(obj, dict):
|
||||
return {k: convert_figures(v, k) for k, v in obj.items()}
|
||||
return obj
|
||||
|
||||
|
||||
# اعراب (کسره، فتحه، ضمه، تشدید، سکون، همزهی رویِ «ه») و «ی»ِ نوشتهشدهی اضافه («پایهی سوم» → «پایه سوم»):
|
||||
# تصمیمِ شرکت (۲۰۲۶-۱۰-۱۴) این است که هیچکدام به کاربر نرسد. تنوین («قبلاً») عمداً میماند: جزئی از املای
|
||||
# معیار است و بیآن غلطِ تایپی به نظر میرسد. «هی» فقط وقتی برداشته میشود که بعدش حرفِ فارسیِ دیگری نچسبیده باشد.
|
||||
_FA_DIACRITICS = re.compile('[\u064C-\u0652\u0654]')
|
||||
# «ه» + نیمفاصله + «ی» که بعدش حرفِ فارسی یا نیمفاصلهی دیگری نیست؛ با «ه» شروع میشود (نه lookbehind) تا موتورِ regex
|
||||
# با جستجوی سریعِ پیشوند جلو برود.
|
||||
_FA_EZAFE_YE = re.compile('\u0647\u200C\u06CC(?![\u0600-\u06FF\u200C])')
|
||||
# همان دو قاعده روی بایتهای UTF-8 (برای متنِ کاملِ پاسخِ JSON): اعراب D9 8C..D9 92 و D9 94 است، و D9 هرگز بایتِ
|
||||
# ادامه نیست، پس با تکهای از نویسهی دیگر یکی نمیشود. حروفِ فارسی/عربی D8..DB و نیمفاصله E2 80 8C.
|
||||
_FA_DIACRITICS_B = re.compile(rb'\xd9[\x8c-\x92\x94]')
|
||||
_FA_EZAFE_YE_B = re.compile(rb'\xd9\x87\xe2\x80\x8c\xdb\x8c(?![\xd8-\xdb]|\xe2\x80\x8c)')
|
||||
|
||||
|
||||
def plain_persian(text):
|
||||
"""متنِ فارسی بیاعراب و بی «ی»ِ اضافه؛ غیرِ رشته دستنخورده. idempotent."""
|
||||
if not isinstance(text, str) or text.isascii():
|
||||
return text
|
||||
return _FA_EZAFE_YE.sub('\u0647', _FA_DIACRITICS.sub('', text))
|
||||
|
||||
|
||||
def plain_persian_utf8(body: bytes) -> bytes:
|
||||
"""plain_persian روی بایتهای UTF-8، بی decode. روی متنِ کاملِ یک پاسخِ JSON درست است: هیچکدام از این نویسهها
|
||||
جزئی از نحوِ JSON نیستند. روی curriculum.jsonِ محلی (۵ مگابایت JSON) حدودِ ۲۷ میلیثانیه، در برابرِ ۵۷ برای خودِ
|
||||
JSONRenderer؛ پاسخِ معمولِ /api/home چند ده کیلوبایت است."""
|
||||
return _FA_EZAFE_YE_B.sub(b'\xd9\x87', _FA_DIACRITICS_B.sub(b'', body))
|
||||
|
||||
Reference in New Issue
Block a user