تخطَّ إلى المحتوى

النصوص في Swift: String وأهم دوالها

الدرس 8 من 11 · Swift

عنوان الشاشة، واسم المستخدم، ونص الإشعار: تطبيقات iPhone تتعامل مع النصوص في كل مكان. تعرّفت على String وعلى إدراج القيم بـ \() في درس المتغيرات. في هذا الدرس ستتعلم أهم دوال النصوص في Swift، وستفهم لماذا تتعامل Swift مع الحروف بطريقة مختلفة قليلاً عن بقية اللغات.

بعض دوال هذا الدرس تأتي من مكتبة Apple الأساسية، فابدأ ملفك بهذا السطر:

import Foundation
let word = "Swift"
print(word.count)
print(word.isEmpty)
print(word.uppercased())
print(word.lowercased())
print(String(word.reversed()))
for letter in "عمر" {
print(letter)
}
الناتج
5
false
SWIFT
swift
tfiwS
ع
م
ر
  • count: عدد الحروف، ويعمل بشكل صحيح مع العربية أيضاً.
  • isEmpty: هل النص فارغ ""؟
  • uppercased() و lowercased(): نسخة جديدة بحروف كبيرة أو صغيرة.
  • reversed() تُرجع الحروف معكوسة، و String(...) تجمعها في نص من جديد.

تخيّل النص مثل عقد من الخرز: كل خرزة حرف، والحلقة for تمر عليها واحدة واحدة.

النص المعرَّف بـ let ثابت. أما المعرَّف بـ var فيمكن تعديله في مكانه:

var greeting = "مرحباً"
greeting += " يا عمر"
greeting.append("!")
print(greeting)
let line = String(repeating: "=", count: 12)
print(line)
الناتج
مرحباً يا عمر!
============
let fileName = "photo.png"
print(fileName.prefix(5))
print(fileName.suffix(3))
print(fileName.dropFirst(6))
print(fileName.dropLast(4))
print(fileName.hasPrefix("photo"))
print(fileName.hasSuffix(".jpg"))
الناتج
photo
png
png
photo
true
false
  • prefix(n) و suffix(n): أول أو آخر n حروف.
  • dropFirst(n) و dropLast(n): النص بعد حذف n حروف من أوله أو آخره.
  • hasPrefix و hasSuffix: هل يبدأ النص أو ينتهي بهذا الجزء؟

في أغلب اللغات تكتب word[0] لأخذ الحرف الأول. في Swift هذا خطأ ترجمة! السبب أن الحرف الواحد الظاهر على الشاشة قد يتكون من عدة أجزاء في الذاكرة (كالحروف المشكولة والرموز التعبيرية)، فلا تستطيع Swift القفز إلى الحرف رقم n مباشرة. لذلك تستخدم نوعاً خاصاً للمواضع اسمه String.Index:

let email = "omar@example.com"
if let at = email.firstIndex(of: "@") {
let user = email[..<at]
let domain = email[email.index(after: at)...]
print(user)
print(domain)
}
let letters = Array("Swift")
print(letters[0])
print(letters[4])
الناتج
omar
example.com
S
t
  • firstIndex(of:): تُرجع موضع أول ظهور للحرف كقيمة اختيارية، ولهذا فتحناها بـ if let.
  • email[..<at]: من البداية إلى ما قبل الموضع. و email[...] بعده: من الموضع إلى النهاية.
  • index(after:): الموضع التالي مباشرة.
  • إذا احتجت الوصول بالأرقام كثيراً، حوّل النص إلى مصفوفة حروف بـ Array(...).

البحث والاستبدال والتنظيف

Section titled “البحث والاستبدال والتنظيف”
let text = " Hello Swift "
let clean = text.trimmingCharacters(in: .whitespaces)
print("[\(clean)]")
print(clean.contains("Swift"))
print(clean.contains("Java"))
print(clean.replacingOccurrences(of: "Swift", with: "World"))
الناتج
[Hello Swift]
true
false
Hello World
  • trimmingCharacters(in: .whitespaces): تحذف المسافات من الطرفين. استخدمها دائماً مع ما يكتبه المستخدم.
  • contains: هل يحتوي النص على هذا الجزء؟
  • replacingOccurrences(of:with:): تستبدل كل ظهور للنص الأول بالثاني.

كلها تُرجع نصاً جديداً ولا تغيّر الأصلي.

let a = "swift"
let b = "SWIFT"
print(a == b)
print(a == b.lowercased())
print("apple" < "banana")
الناتج
false
true
true

== تقارن محتوى النصين، والمقارنة حساسة لحالة الحروف. لتجاهل الحالة وحّد النصين بـ lowercased() أولاً. و < تقارن أبجدياً.

let csv = "تفاح,موز,عنب"
let fruits = csv.components(separatedBy: ",")
print(fruits.count)
print(fruits[1])
print(fruits.joined(separator: " - "))
let sentence = "تعلّم البرمجة ممتع جداً"
print(sentence.split(separator: " ").count)
الناتج
3
موز
تفاح - موز - عنب
4
  • components(separatedBy:): تقطع النص عند الفاصل وتُرجع مصفوفة [String].
  • joined(separator:): تدمج مصفوفة نصوص في نص واحد.
  • split(separator:): مثل الأولى لكنها تُرجع [Substring] وتتجاهل الأجزاء الفارغة.

لكتابة نص طويل على عدة أسطر، استخدم ثلاث علامات تنصيص:

let name = "ليلى"
let message = """
مرحباً \(name)،
تم تسجيلك بنجاح.
رقم طلبك: \(100 + 23)
"""
print(message)
الناتج
مرحباً ليلى،
تم تسجيلك بنجاح.
رقم طلبك: 123

موضع علامات الإغلاق """ يحدد الإزاحة التي تُحذف من أول كل سطر، فيبقى كودك مرتباً والنص نظيفاً.

ما يكتبه المستخدم في حقل الإدخال يصلك نصاً دائماً. التحويل بـ Int(...) يُرجع قيمة اختيارية، لأن النص قد لا يكون رقماً:

let inputs = ["42", "abc", "7"]
for input in inputs {
if let number = Int(input) {
print("العدد \(number) وضعفه \(number * 2)")
} else {
print("\(input) ليس رقماً")
}
}
let price = Double("19.5") ?? 0
print(price + 0.5)
print("العمر: " + String(15))
الناتج
العدد 42 وضعفه 84
abc ليس رقماً
العدد 7 وضعفه 14
20.0
العمر: 15

لا استثناءات ولا انهيار: إما رقم، أو nil تتعامل معه بـ if let أو ??. و String(15) تحوّل الرقم إلى نص.

  1. خزّن جملة في ثابت، واطبع عدد حروفها وعدد كلماتها.
  2. خزّن اسم ملف مثل report.pdf، واستخرج الامتداد بعد النقطة باستخدام components(separatedBy:) و last.
  3. اكتب دالة initials(of fullName: String) -> String تُرجع الحرف الأول من كل كلمة: "Omar Ali" تصبح "OA".
  4. تحدٍّ: اكتب دالة isPalindrome(_ word: String) -> Bool تُرجع true إذا كانت الكلمة تُقرأ من الجهتين بنفس الشكل مثل level، مع تجاهل حالة الحروف.
  • الوصول برقم: word[0] خطأ ترجمة في Swift. استخدم word.first أو prefix أو حوّل النص إلى Array.
  • دمج نص مع رقم: "العمر: " + 15 خطأ، فالنوعان مختلفان. استخدم الإدراج "العمر: \(15)" أو String(15).
  • نسيان أن التحويل اختياري: Int("12") + 1 خطأ ترجمة، لأن الناتج Int?. افتحه بـ if let أو ??.
  • تجاهل القيمة المُرجعة: text.uppercased() وحدها لا تغيّر text. خزّن النتيجة في ثابت جديد.

سؤال

ما ناتج "Hello".prefix(2)؟

سؤال

ما قيمة Int("12a")؟

  • count لعدد الحروف، و uppercased() و lowercased() و reversed() لتحويل النص.
  • prefix و suffix و dropFirst و dropLast لأخذ أجزاء من الطرفين.
  • لا وصول بالأرقام: استخدم String.Index أو حوّل النص إلى Array.
  • components(separatedBy:) تقسم، و joined(separator:) تدمج، و """ لعدة أسطر.
  • Int(...) و Double(...) يُرجعان قيمة اختيارية تفتحها بـ if let أو ??.