مقدمة: "المفاجأة" التي تنتظر كل مطور Swift
\n\nتخيل الموقف: أنت تكتب كودًا بثقة في Swift، كل شيء يسير بسلاسة، وفجأة تحتاج إلى أخذ أول ثلاثة أحرف من سلسلة نصية. تكتب دون تفكير شيئًا مثل myString[0..<3] — وتحصل على... خطأ في الترجمة. هل هذا مألوف؟
مرحبًا بك في عالم String substring في Swift. هذا أحد المواضيع التي تسبب ألمًا حقيقيًا للمبتدئين وحتى للمطورين ذوي الخبرة القادمين من لغات أخرى. سؤال "How does String substring work in Swift" على Stack Overflow حصد آلاف المشاهدات — وهذا ليس من قبيل الصدفة.
\n\nفي هذه المقالة، سنشرح لماذا Swift "غريب" في التعامل مع السلاسل الفرعية، وكيفية استخدام substring في Swift بشكل صحيح، وما هي الإمكانيات الجديدة التي ظهرت في الإصدارات الأخيرة. هيا بنا!
\n\nلماذا لا يسمح Swift ببساطة بأخذ جزء من السلسلة النصية؟
\n\nفي معظم اللغات (Python, JavaScript, C#) السلسلة النصية هي مجرد مصفوفة من الأحرف. تريد سلسلة فرعية؟ اكتب str[0:3] واحصل على النتيجة. في Swift الأمر مختلف.
السبب يكمن في التعامل مع Unicode. السلاسل النصية في Swift ليست مجرد بايتات أو أحرف ASCII. إنها تتكون من مجموعات حروف رسومية (grapheme clusters). الحرف الواحد الذي يراه المستخدم (مثل "é" أو "👍🏽") قد يشغل عدة Character أو حتى عدة Unicode.Scalar. تخيل أنك تقطع السلسلة النصية في منتصف هذه المجموعة — ستحصل على بيانات تالفة.
لذلك يستخدم Swift المؤشرات (String.Index) بدلاً من الأعداد الصحيحة. هذا يضمن أنك لن تقطع حرفًا إلى نصفين أبدًا.
الأساسيات: String.Index واستخراج سلسلة فرعية بسيطة
\n\nلنبدأ بمثال أساسي. لنفترض أن لدينا سلسلة نصية:
\n\nlet fullString = "مرحبًا، Swift!"\n// نريد أخذ كلمة "Swift"\nlet startIndex = fullString.index(fullString.startIndex, offsetBy: 8)\nlet endIndex = fullString.index(fullString.startIndex, offsetBy: 13)\nlet substring = fullString[startIndex..<endIndex]\nprint(substring) // سيطبع: "Swift"\n\nلاحظ: substring من النوع Substring وليس String. هذا فرق مهم. Substring هي "نافذة" على السلسلة النصية الأصلية. إنها لا تنسخ البيانات، بل تشير فقط إلى جزء من ذاكرة السلسلة النصية الأصلية. هذا فعال للغاية، لكنه قد يؤدي إلى تسرب للذاكرة إذا كانت السلسلة النصية الأصلية كبيرة والفرعية صغيرة.
لتحويل Substring إلى String كاملة، استخدم المُهيئ:
let newString = String(substring)\nprint(newString) // "Swift"\n\nالسكر النحوي: RangeExpression
\n\nكتابة index(offsetBy:) في كل مرة أمر متعب. لحسن الحظ، يسمح Swift باستخدام صيغ أقصر باستخدام RangeExpression.
العامل ... (ClosedRange)
\nlet str = "Hello, World!"\nif let range = str.range(of: "World") {\n let worldSubstring = str[range]\n print(worldSubstring) // "World"\n}\n\nالنطاقات الجزئية (Partial Range)
\nهل تريد أخذ كل شيء حتى مؤشر معين أو بعده؟ بسهولة:
\nlet text = "Swift Programming"\nlet prefix = text[..<text.index(text.startIndex, offsetBy: 5)]\nprint(prefix) // "Swift"\n\nlet suffix = text[text.index(text.startIndex, offsetBy: 6)...]\nprint(suffix) // "Programming"\n\nلاحظ: prefix و suffix هما أيضًا من النوع Substring.
الطرق المضمنة: prefix, suffix, dropFirst, dropLast
\n\nيوفر Swift طرقًا ملائمة تغنيك عن حساب المؤشرات يدويًا. تعيد هذه الطرق Substring.
- \n
str.prefix(5)— أول 5 أحرف. \n str.suffix(3)— آخر 3 أحرف.