تقنية

surrogateescape في بايثون: أعد البايتات التي تعذّر فكها دون فقدها

بايتات أصلية، ثم تمثيلها المحفوظ، ثم البايتات نفسها بعد الإعادة.
المسار يستخدم ⁦UTF-8⁩ وsurrogateescape في الاتجاهين. [2]

يحفظ surrogateescape البايتات التي تعذّر فكها؛ استرجعها بالترميز نفسه ومعالج الأخطاء نفسه. [2]

اختُبرت المقاطع باستخدام ⁦Python 3.12.14⁩، مع الرجوع إلى وثائق ⁦Python 3.14⁩؛ شغّلها بالترتيب في الجلسة نفسها.

الخلاصة السريعة

  • يرفض strict خطأ فك الترميز، وهو السلوك الافتراضي؛ لا يحذف البايت غير الصالح بصمت. [1]
  • في هذا المثال، تحفظ surrogateescape البايت 128 بالرمز ⁦U+DC80⁩؛ إعادة الترميز بالطريقة نفسها تعيد البايتات الأصلية. [2]
  • تُعيد encode بايتات، وتستخدم strict افتراضيًا؛ نسيان معالج الأخطاء عند إعادة هذا النص يثير خطأً. [2] [3]
  • يستبدل replace خطأ فك الترميز بالمحرف ⁦U+FFFD⁩؛ إعادة ترميزه هنا لا تسترجع البايت الأصلي. [1] [3]

ابدأ ببايتات ترفضها القراءة الافتراضية

يرفض strict خطأ فك الترميز، وهو السلوك الافتراضي؛ لا يحذف البايت غير الصالح بصمت. [1]

أنشأنا ثلاثة بايتات في الذاكرة. يطبع المقطع ⁦decode failed⁩ لأن البايت الأوسط لا يصلح وحده في ⁦UTF-8⁩. نحافظ على raw للمقارنة اللاحقة؛ لم نقرأ ملفًا أو نخمن ترميزه. [1]

مرّر الشيفرة أفقيًا عند الحاجة.

raw = bytes([99, 128, 100])
try:
    raw.decode("utf-8")
except UnicodeDecodeError:
    print("decode failed")

احفظ البايت ثم أعده كما كان

في هذا المثال، تحفظ surrogateescape البايت 128 بالرمز ⁦U+DC80⁩؛ إعادة الترميز بالطريقة نفسها تعيد البايتات الأصلية. [2]

يطبع المقطع True؛ قارنّا البايتات نفسها. لا تغيّر text قبل الإعادة. [2] [3]

الرموز من ⁦U+DC80⁩ إلى ⁦U+DCFF⁩ تحفظ البايتات؛ لا تكتشف الترميز أو تصلح المعنى. [2]

مرّر الشيفرة أفقيًا عند الحاجة.

text = raw.decode("utf-8", errors="surrogateescape")
back = text.encode("utf-8", errors="surrogateescape")
print(back == raw)  # True

لا تنس إعداد الإعادة

تُعيد encode بايتات، وتستخدم strict افتراضيًا؛ نسيان معالج الأخطاء عند إعادة هذا النص يثير خطأً. [2] [3]

أعد تحديد errors في كل استدعاء encode؛ الإعداد الافتراضي strict يثير الخطأ هنا. [2] [3]

مرّر الشيفرة أفقيًا عند الحاجة.

try:
    text.encode("utf-8")
except UnicodeEncodeError:
    print("encode failed")

قارن مع الاستبدال قبل اختيار المعالج

يستبدل replace خطأ فك الترميز بالمحرف ⁦U+FFFD⁩؛ إعادة ترميزه هنا لا تسترجع البايت الأصلي. [1] [3]

يطبع المقطع False. إذا كان هدف العملية الاحتفاظ بالأصل لإعادته لاحقًا، فهذه النتيجة تكشف فشل مسار الاستبدال في المثال. نجاح تحويل النص إلى بايتات لا يعني استرجاع المدخل نفسه. [1] [3]

مرّر الشيفرة أفقيًا عند الحاجة.

changed = raw.decode("utf-8", errors="replace").encode("utf-8")
print(changed == raw)  # False

المصادر ومتابعة القراءة

  1. Python: معالجات أخطاء الترميز (يفتح في نافذة جديدة)docs.python.org
  2. PEP 383: حفظ البايتات وإعادتها (يفتح في نافذة جديدة)peps.python.org
  3. Python: الدالة str.encode (يفتح في نافذة جديدة)docs.python.org

أُعدّ هذا المقال بصياغة عربية أصلية بالاستناد إلى المصادر أعلاه، وهو مدخل تمهيدي إلى الموضوع. اقرأ منهجية المحتوى وحدوده.