مسیرها
/
Swift
Swift
/
تمرین‌ها
/
قانون اول باشگاه شعر
قانون اول باشگاه شعر

قانون اول باشگاه شعر

تمرین یادگیری

مقدمه

وارد کردن

زبان Swift قابلیت‌های فراوانی در کتابخانه‌ی استاندارد خود ارائه می‌دهد، اما می‌توانید با وارد کردن کتابخانه‌ها و frameworkهای بیرونی به امکانات بیشتری دسترسی پیدا کنید. این ماژول‌ها ممکن است مستقیماً از پروژه‌ی Swift بیایند (مانند Swift Argument Parser)، از frameworkهای پلتفرم Apple (مانند Foundation و Network Framework)، یا از کتابخانه‌های متن‌باز شخص ثالث (مانند SwiftyBeaver).

ماژول‌های اصلی مانند Foundation، که یکی از پرکاربردترین کتابخانه‌ها در Swift است، همراه با زنجیره‌ی ابزار Swift ارائه می‌شوند. کتابخانه‌های شخص ثالث باید پیش از آن که بتوان آن‌ها را وارد کرد، به پیکربندی پروژه‌تان افزوده شوند (برای نمونه، با استفاده از Swift Package Manager).

وارد کردن ماژول‌ها با نوشتن کلیدواژه‌ی import و سپس اسم ماژول انجام می‌شود. بنابراین می‌توانید با افزودن قطعه‌ی زیر به برنامه‌تان، Foundation را وارد کنید.

import Foundation

وارد کردن یک ماژول، نوع‌ها، متدها و توابع آن را در اختیار کد شما قرار می‌دهد. برای نمونه، وارد کردن Foundation، String را با متدهای سودمند و کاربردی مانند components(separatedBy:) گسترش می‌دهد.

طبق قرارداد، دستورهای import در بالای فایل Swift نوشته می‌شوند تا وابستگی‌ها بی‌درنگ برای هر کسی که کد را می‌خواند آشکار باشد.

اندیس‌گذاری رشته

به کاراکترهای تک‌تک یک String می‌توان با همان روش اندیس‌گذاری آرایه‌ها دسترسی پیدا کرد. اما اندیس‌هایی که برای رشته‌ها به کار می‌روند عدد صحیح نیستند و نمی‌توان مستقیماً با آن‌ها کار کرد. در عوض باید آن‌ها را بر پایه‌ی اندیس شناخته‌شده‌ی دیگری مانند startIndex محاسبه کرد، که به جایگاه نخستین کاراکتر در یک رشته‌ی ناتهی اشاره می‌کند؛ این کار با متدهای موجود در کتابخانه‌های String و NSString انجام می‌شود (وقتی ماژول Foundation وارد شده باشد، رشته‌ها در Swift به همه‌ی ویژگی‌ها و متدهای NSString دسترسی دارند).

برای نمونه، رشته‌ی زیر را در نظر بگیرید:

let csv = "apple,pear,peach,orange,cherry,lime,goosberry"

نمی‌توان برای به دست آوردن «g» در «orange» عبارت csv[21] را نوشت؛ در عوض باید مقداری از نوع String.Index محاسبه کرد و همان اندیس را به کار برد. توجه کنید که این اندیس‌ها به خودی خود برای مصرف انسان در نظر گرفته نشده‌اند. به آن‌ها اندیس‌های مبهم می‌گویند، چون انسان‌ها نیازی ندارند بدانند درونشان چیست.

let index = csv.index(csv.startIndex, offsetBy: 21)
csv[index]
// "g"
print(index)
// prints Index(_rawBits: 1376513)

اما توجه کنید که اگر مقدار offset اندیس معتبری نباشد، یعنی اگر اندیسی پیش از startIndex یا پس از endIndex برگرداند، این عملیات خطا ایجاد می‌کند و برنامه از کار می‌افتد. برای جلوگیری از این مشکل، می‌توان یک اندیس محدودکننده تعیین کرد. این کار یک اندیس اختیاری برمی‌گرداند و برای اندیس‌های نامعتبر nil را برمی‌گرداند.

let tooFar = csv.index(csv.startIndex, offsetBy: 200)
// error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
let tooFarButSafe = csv.index(csv.startIndex, offsetBy: 200, limitedBy: csv.endIndex)
// nil

افزون بر این، اندیس‌ها را نمی‌توان بین رشته‌ها به اشتراک گذاشت. برای نمونه، اگر از index مربوط به «g» در «orange» که بالا محاسبه شد برای اندیس‌گذاری در رشته‌ی fam = "This is my family: 👨‍👩‍👦‍👦, this is our dog: 🐶, this is our cat: 🐱!" استفاده کنید، یعنی fam[index]، برنامه‌تان از کار می‌افتد.

دلایل زیادی برای همه‌ی این‌ها وجود دارد، اما همه‌شان در یک چیز خلاصه می‌شوند: «Unicode پیچیده است».

به طور کلی، اگر به دسترسی تصادفی به کاراکترهای تک‌تک نیاز دارید، به احتمال زیاد بهتر است از ساختار داده‌ی دیگری مانند Array<Character> استفاده کنید.

چند متد سودمند

Swift متدهای first و last را برای گرفتن نخستین و آخرین کاراکتر یک رشته دارد. این متدها یک کاراکتر اختیاری برمی‌گردانند، پس اگر رشته خالی باشد، nil برمی‌گردانند.

let str = "Hello, world!"
print(str.first) // Prints Optional("H")
print(str.last)  // Prints Optional("!")

همچنین می‌توانید از متدهای prefix و suffix برای گرفتن زیررشته‌ای از یک رشته استفاده کنید. این متدها یک عدد صحیح به عنوان آرگومان می‌گیرند و زیررشته‌ای شامل n کاراکتر نخست یا پایانی رشته برمی‌گردانند.

let str = "Hello, world!"
print(str.prefix(5)) // Prints "Hello"
print(str.suffix(6)) // Prints "world!"

متدهای رشته

کار کردن با متن، یکی از کارهای رایج در برنامه‌نویسی است. Swift، همراه با framework Foundation، متدها و ویژگی‌های فراوان و سودمندی برای بررسی، تغییر و دستکاری رشته‌ها در اختیار می‌گذارد.

تقسیم رشته‌ها با components(separatedBy:)

برای تقسیم یک رشته به آرایه‌ای از زیررشته‌ها بر پایه‌ی یک جداکننده، از components(separatedBy:) استفاده کنید (نیازمند وارد کردن Foundation است):

import Foundation

let sentence = "Hello, world!"
let words = sentence.components(separatedBy: " ")
print(words) // Prints ["Hello,", "world!"]

بررسی پیشوندها و پسوندها با hasPrefix(_:) و hasSuffix(_:)

برای بررسی این که یک رشته با دنباله‌ی مشخصی از کاراکترها آغاز یا پایان می‌یابد، از hasPrefix(_:) و hasSuffix(_:) استفاده کنید:

let greeting = "Hello, world!"
print(greeting.hasPrefix("Hello"))  // Prints true
print(greeting.hasSuffix("world!")) // Prints true

تغییر حروف بزرگ و کوچک

می‌توانید بزرگی و کوچکی حروف یک رشته را با این متدها و ویژگی‌های استاندارد تغییر دهید:

  • lowercased(): نسخه‌ای از رشته با حروف کوچک برمی‌گرداند.
  • uppercased(): نسخه‌ای از رشته با حروف بزرگ برمی‌گرداند.
  • capitalized: نسخه‌ای برمی‌گرداند که نخستین حرف هر واژه در آن بزرگ است (از Foundation).
let greeting = "hello, world!"
print(greeting.lowercased())  // Prints "hello, world!"
print(greeting.uppercased())  // Prints "HELLO, WORLD!"
print(greeting.capitalized)   // Prints "Hello, World!"

جایگزینی زیررشته‌ها با replacingOccurrences(of:with:)

برای جایگزین کردن همه‌ی رخدادهای یک زیررشته‌ی هدف با رشته‌ی دیگری، از replacingOccurrences(of:with:) استفاده کنید (از Foundation):

let greeting = "Hello, world!"
let updated = greeting.replacingOccurrences(of: "world", with: "Swift")
print(updated) // Prints "Hello, Swift!"

پیوستن رشته‌ها با joined(separator:)

متد joined(separator:) به مجموعه‌هایی از رشته‌ها، مانند [String]، تعلق دارد. این متد عنصرها را با یک جداکننده به هم می‌پیوندد و به یک رشته‌ی واحد تبدیل می‌کند:

let words = ["Hello", "world"]
let sentence = words.joined(separator: ", ")
print(sentence) // Prints "Hello, world"

دستورالعمل‌ها

یک باشگاه شعر تازه در شهر باز شده است و شما به فکر رفتن به آن هستید. چون در گذشته اتفاق‌هایی رخ داده است، این باشگاه آیین‌نامه‌ی ورود بسیار خاصی دارد که باید پیش از تلاش برای ورود، بر آن مسلط شوید.

باشگاه شعر دو در دارد و هر دو نگهبان دارند. برای این که اجازه‌ی ورود بگیرید، باید رمز آن روز را کشف کنید:

1. تقسیم یک رشته به خطوط جداگانه

اولین کاری که باید انجام دهید، تقسیم شعر به خطوط جداگانه است. نگهبان شعری می‌خواند و شما باید آن را به خطوط تقسیم کنید.

تابع splitOnNewlines را پیاده‌سازی کنید که یک رشته می‌گیرد و آن را با استفاده از کاراکتر خط جدید به عنوان جداکننده، به آرایه‌ای از رشته‌ها تقسیم می‌کند. تابع باید آرایه‌ای از رشته‌ها برگرداند که هر رشته یکی از خطوط شعر است.

splitOnNewlines("Hello.\nHow are you?\n\nI'm doing fine.")
// returns ["Hello." ,"How are you?", "", "I'm doing fine"].

2. در ورودی

  1. نگهبان شعری می‌خواند.
  2. باید شعر را به خطوط جداگانه تقسیم کنید.
  3. باید اولین حرف هر خط را بردارید.
    • اگر خط خالی باشد، باید به جای آن از _ استفاده کنید.
  4. باید حروف را کنار هم بگذارید تا یک واژه بسازند.

برای نمونه، یکی از نویسندگان محبوبشان Michael Lockwood است که شعر آکروستیک زیر را نوشته است؛ یعنی حرف اول هر جمله یک واژه می‌سازد:

Stands so high
Huge hooves too
Impatiently waits for
Reins and harness
Eager to leave

وقتی نگهبان شعر را می‌خواند، شما آن را به خطوط جداگانه تقسیم می‌کنید و با حرف اول هر خط پاسخ می‌دهید، یعنی ["S", "H", "I", "R", "E"].

سپس نگهبان واژه‌ای را که از آرایه‌ی حروف پاسخ شما ساخته شده است به شما می‌دهد تا آن را به شکل واژه‌ای با حرف اول بزرگ درآورید. در نهایت رمزی که برمی‌گردانید "SHIRE" است و اجازه‌ی ورود می‌گیرید.

تابع frontDoorPassword را پیاده‌سازی کنید که رشته‌ای را که نماینده‌ی شعر است می‌گیرد. تابع باید رمزی را برگرداند که به نگهبان می‌دهید.

frontDoorPassword("Stands so high\nHuge hooves too\nImpatiently waits for\nReins and harness\nEager to leave")
// returns "SHIRE"

3. در پشتی

در پشت باشگاه، نامدارترین شاعران را می‌بینید که چیزی شبیه منطقه‌ی VIP است. چون این بخش برای همه نیست، روند در پشتی کمی پیچیده‌تر است.

  1. نگهبان شعری می‌خواند.
  2. باید شعر را به خطوط تقسیم کنید.
  3. باید آخرین حرف هر خط را بردارید.
    • گاهی خط در انتها فاصله دارد، پس باید آن‌ها را حذف کنید.
  4. باید حروف را کنار هم بگذارید و سپس ", please" را به انتهای واژه‌ای که از حروف ساخته می‌شود اضافه کنید.

برای نمونه، شعر پیش‌گفته تلستیک هم هست؛ یعنی آخرین حرف هر جمله یک واژه می‌سازد:

Stands so high
Huge hooves too
Impatiently waits for
Reins and harness
Eager to leave

وقتی نگهبان شعر را می‌خواند، شما آن را به خطوط جداگانه تقسیم می‌کنید، فاصله‌های انتهایی را حذف می‌کنید و با حرف اول هر خط پاسخ می‌دهید، یعنی ["h", "o", "r", "s", "e"].

سپس نگهبان واژه‌ای را که از آرایه‌ی حروف پاسخ شما ساخته شده است به شما می‌دهد تا آن را به شکل واژه‌ای با حرف اول بزرگ درآورید و ", please" را به آن اضافه کنید. در نهایت رمزی که برمی‌گردانید "horse, please" است و اجازه‌ی ورود می‌گیرید.

تابع backDoorPassword را پیاده‌سازی کنید که رشته‌ای را که نماینده‌ی شعر است می‌گیرد. تابع باید رمزی را برگرداند که به نگهبان می‌دهید.

backDoorPassword("Stands so high\nHuge hooves too\nImpatiently waits for\nReins and harness\nEager to leave")
// returns "horse, please"

4. اتاق مخفی

در انتهای اتاق پشتی باشگاه دری دیگر هست که به اتاق مخفی می‌رسد؛ اتاقی که فقط برترین شاعران می‌توانند وارد آن شوند.

  1. نگهبان شعری می‌خواند.
  2. باید شعر را به خطوط تقسیم کنید.
  3. باید حرف iاُم خط iاُم را بردارید.
  4. باید حروف را کنار هم بگذارید و سپس "!" را به انتهای واژه‌ای که از حروف ساخته می‌شود اضافه کنید.
  5. باید واژه را به شکل حروف بزرگ درآورید.

برای نمونه، نسخه‌ی تغییریافته‌ای از شعر پیش‌گفته با این الگو جور درمی‌آید:

Stands so high
Huge hooves too
Impatiently waits for
Rider with harness
Eager to leave

وقتی نگهبان شعر را می‌خواند، شما آن را به خطوط جداگانه تقسیم می‌کنید، فاصله‌های انتهایی را حذف می‌کنید و با حرف‌های iاُم هر خط پاسخ می‌دهید، یعنی ["S", "u", "p", "e", "r"].

سپس نگهبان واژه‌ای را که از آرایه‌ی حروف پاسخ شما ساخته شده است به شما می‌دهد تا آن را به شکل واژه‌ای با حروف بزرگ درآورید و "!" را به آن اضافه کنید. در نهایت رمزی که برمی‌گردانید SUPER! است و اجازه‌ی ورود می‌گیرید.

تابع secretRoomPassword را پیاده‌سازی کنید که رشته‌ای را که نماینده‌ی شعر است می‌گیرد. تابع باید رمزی را برگرداند که به نگهبان می‌دهید.

secretRoomPassword("Stands so high\nHuge hooves too\nImpatiently waits for\nRider with harness\nEager to leave")
// returns "SUPER!"
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Swift Exercism

آماده‌اید قانون اول باشگاه شعر را شروع کنید؟

در Exercism ثبت‌نام کنید تا Swift را همراه با 35 مفهوم116 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.