تقنية

طي سطر iCalendar بالعربية: احسب البايتات ثم استعد النص

حساب مثال ب: الجزء الأول74 والثاني15، ويصبح الناتج93 بايت مع نهايتي السطر.
كتل مثالنا العربي وأطوالها التي أعادتها الشيفرة.

يوصي RFC 5545 بألا يتجاوز السطر 75 بايت، باستثناء CRLF؛ هذه SHOULD وليست حكما ببطلان كل تجاوز. يُطوى بين محرفين بإضافة CRLF ومسافة أو تبويب، وتزال علامة الاستمرار عند الفك. [1]

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

  • سطرنا العربي: 48 محرفا، لكن 88 بايت قبل الطي.
  • في تجربتنا صار السطران العربيان 74 و15 بايت، مع مسافة الاستمرار.
  • السطر اللاتيني له 88 بايت أيضا، لكنه انقسم إلى75 و14.
  • بقيت المسافة الأصلية في المثال الثالث بعد الاستعادة؛ نجحت المقارنات الثلاث.

حدد النص الذي سنقيسه

بنينا ثلاثة أسطر تبدأ بالنص SUMMARY:، وعدد محارف هذه البداية ثمانية. أكملنا الأول بأربعين حرف ب، والثاني بثمانين حرف A. في الثالث أضفنا66 حرف B، ثم مسافة واحدة، ثم عشرة أحرف ن. هذه نصوص مختبرية اختيرت لتظهر حدود الفصل بوضوح؛ لا تمثل أسماء مواعيد حقيقية.

نتتبع في الجدول ثلاثة أعداد مختلفة: حجم النص الأصلي، وطول كل جزء في الناتج، وحجم الناتج كله. تشمل الخانة الأخيرة علامتي نهاية السطر في هذا المثال ذي الجزأين. لذلك لا تتوقع أن يساوي جمع طولي الجزأين حجم البايتات الكامل.

لماذا توقف مثال ب عند74؟

في النص الأول حسبنا ثمانية بايتات للبداية وثمانين للأحرف الأربعين، فكان المجموع88. وضعت دالتنا33 حرف ب بعد البداية؛ بلغ الجزء الأول74. كان إدخال الحرف التالي سيجعله76، ولذلك انتقل الحرف إلى الجزء الثاني في التنفيذ الذي أمامنا.

احتوى الجزء الثاني مسافة أضافتها الدالة وسبعة أحرف ب، فصار طوله15. ومع نهايتي السطر جاء الناتج93 بايت:74+15+2+2. هذه هي الأرقام التي طبعها برنامجنا؛ الرسم يعرض كتلها بدلا من تكرار أربعين حرفا صغيرا.

عدد متساو، وقسمتان مختلفتان

وصل المثال اللاتيني إلى88 بايت قبل الطي أيضا. لكن جزأيه في سجلنا كانا75 و14، لا74 و15. احتوى الأول على البداية و67 حرف A، وبقي13 حرفا للجزء الذي بدأ بالمسافة المضافة. ومع نهايتي السطر ظل الحجم الكامل93.

تساوي الحجم الكلي هنا لم ينتج عنه تطابق موضع الفصل. تستطيع مقارنة ملفي التجربة بايتا ببايت، وستجد أن أول جزء عربي انتهى أبكر ببايت واحد. لهذا احتفظنا بأطوال الأجزاء منفصلة في الجدول؛ خانة الحجم الكامل وحدها كانت ستخفي الفرق.

مثالنابايتات الأصلبايتات الجزأينالناتج مع النهايات
ب ×408874 ثم1593
A ×808875 ثم1493
B ومسافة ثم ن9575 ثم21100

مسافة مقصودة في النص الثالث

وضعت الدالة بداية المثال الثالث مع66 حرف B والمسافة الأصلية في الجزء الأول، فبلغ75 بايت. بدأ الجزء الثاني بمسافة أضافتها الدالة، ثم عشرة أحرف ن، فبلغ21. كان النص الأصلي95 بايت، والناتج الكامل100.

بعد الاستعادة قارنا النص كله بالأصل، بما فيه المسافة الواقعة بين آخر B وأول ن؛ أعادت المقارنة True. ثم جربنا فحصا سلبيا يحذف جميع المسافات من النص المستعاد، ففشل التطابق في هذه الحالة. الفرق المقصود ظاهر في الرسم الثاني عند العلامة البرتقالية.

المثال الثالث قبل الطي وبعده وبعد الاستعادة، مع إبراز المسافة الأصلية التي بقيت بين B ون.
في مثالنا الثالث بقيت المسافة البرتقالية؛ حذفت الاستعادة المسافة المضافة وحدها.

شيفرة الحالات الثلاث

نفذنا النص التالي باستخدام Python 3.12.14. يطبع لكل حالة عدد المحارف، وحجم الترميز، وأطوال الأجزاء، وحجم الناتج. العبارة الأخيرة في الحلقة قارنت كل نص مستعاد بالأصل؛ اكتملت الحالات الثلاث دون فشل. لا تكتب هذه الشيفرة ملفات على القرص.

احتفظنا بفحص منفصل أعاد الحساب في Node وقارن البايتات، لا لقطة شاشة للنص. وفي فحص آخر قسمنا المثال العربي اعتباطا عند البايت75؛ فشل فك ترميز الجزء الأول، بينما نجح بعد إعادة جمع البايتات. لم نستخدم ذلك الفصل المعيب لصنع الأجزاء الثلاثة في جدولنا.

def fold(text):
    parts = [b""]
    for char in text:
        unit = char.encode("utf-8")
        if len(parts[-1])+len(unit) > 75:
            parts.append(b" ")
        parts[-1] += unit
    return b"\r\n".join(parts)+b"\r\n"

cases = ["SUMMARY:"+"ب"*40, "SUMMARY:"+"A"*80,
         "SUMMARY:"+"B"*66+" "+"ن"*10]
for text in cases:
    wire = fold(text)
    lines = wire.split(b"\r\n")[:-1]
    restored = wire.replace(b"\r\n ",b"")[:-2]
    print(len(text),len(text.encode()),list(map(len,lines)),len(wire))
    assert restored.decode("utf-8") == text

[1]

ما الذي أثبتته التجربة؟

لدينا ثلاثة نصوص محددة، وأطوال مقاسة، وثلاث مطابقات ناجحة. إعادة التجربة بتغيير عدد الأحرف مفيدة بشرط أن تحتفظ بالنص الأصلي للمقارنة، لا أن تكتفي بعبارة مطبوعة تقول إن الإجراء انتهى. في حالتنا الثالث هو الذي كشف أثر حذف المسافة الأصلية.

لم نبن ملف تقويم كاملا ولم نستورد موعدا في أي خدمة. نطاق العمل هنا تمثيل أسطر المحتوى واستعادة نصوصها. لذلك لا تحول نجاح هذه المقارنات إلى وعد بتوافق موعد كامل؛ خصائص الموعد وتواريخه لم تدخل تجربة البايتات هذه.

المراجع

  1. RFC 5545 — 3.1
    https://www.rfc-editor.org/rfc/rfc5545.html

أُعدّ هذا المقال بمساعدة الذكاء الاصطناعي وراجعته أدوات ذكاء اصطناعي. لا يُنسب إلى مراجع بشري أو خبير مستقل. منهجية المحتوى.