JavaRush /Курси /Swift SELF /Рядкові літерали в Swift: екранування і raw-рядки

Рядкові літерали в Swift: екранування і raw-рядки

Swift SELF
Рівень 7 , Лекція 1
Відкрита

1. Літерали рядків

Коли ви пишете рядок у коді, може здатися, що це найпростіша частина застосунку: взяли текст у лапки — і готово. Але це справедливо лише доти, доки в тексті не з’являються лапка, перенесення рядка, табуляція або зворотний слеш. А вони, як на зло, з’являються дуже швидко. Сьогодні ми побудуємо просту й передбачувану модель: як записати текст всередині вихідного коду так, щоб застосунок надрукував саме те, чого ви очікуєте, а не влаштував сюрприз.

У цій лекції ми говоримо саме про літерали рядків — тобто рядки, які ви пишете прямо в коді: "Hello", """Hello\nWorld""", #"C:\Temp"# і так далі. Це фундамент, на якому зручно будувати акуратний вивід, парсинг, перевірку форматів і все інше.

Звичайний рядковий літерал у Swift — це текст у подвійних лапках. Він читається просто: усе, що всередині лапок, стає значенням типу String. І тут важливо одразу запам’ятати одне «доросле» правило: компілятор не вгадує ваші наміри, а суворо дотримується синтаксису. Якщо всередині рядка трапляється щось, що схоже на спеціальну послідовність, Swift трактуватиме це як команду, а не як набір символів.

Найпростіший приклад:

import Foundation

let greeting = "Hello, Swift!"
print(greeting) // Hello, Swift!

Тут усе прозоро: рядок починається на першій " і закінчується на другій ". Усередині — звичайний текст.

Проблема виникає тоді, коли вам потрібно написати всередині рядка такий самий символ лапки ". Якщо просто вставити лапку, компілятор вирішить, що рядок закінчився, а далі почнеться «каша» з незрозумілих токенів.

String у Swift — value type

У Swift рядок (String) — це value type, тобто тип за значенням. Це означає, що рядок поводиться як самостійне значення: коли ви присвоюєте його іншій змінній, ви працюєте вже з окремою копією, а не зі «спільною коробкою на двох».

Поки що це можна запам’ятати дуже просто: за своєю поведінкою рядок у Swift ближчий до числа, ніж до «спільного об’єкта». Наприклад:

import Foundation

var a = "Hello"
var b = a

b += ", world"

print(a) // Hello
print(b) // Hello, world

Зміна b не змінює a. Для нас зараз важлива саме ця інтуїція: рядок у Swift — це значення, а не посилання на щось спільне. Пізніше, коли ми докладніше говоритимемо про value types, ця ідея стане ще зрозумілішою.

2. Екранування: зворотний слеш і escape-послідовності

Ключова ідея така: всередині звичайного рядкового літерала є символ зворотний слеш \. Він працює як режим «далі буде спецкоманда». Це називається escape-послідовність (в українській часто кажуть «екранування»). Сенс простий: записати в рядку те, що напряму писати не можна, або вказати керівний символ.

Найкорисніші escape-послідовності зручно тримати в голові як невелику таблицю:

Що потрібно отримати в рядку Як написати в коді Що це означає
Лапка " всередині рядка
\"
«Це не кінець рядка, а символ лапки»
Зворотний слеш \
\\
«Перший слеш вмикає екранування, другий стає символом»
Перенесення рядка
\n
Перехід на новий рядок
Табуляція
\t
Горизонтальний відступ, як у таблицях

Лапка всередині рядка: \"

Уявіть, що ви хочете вивести фразу: He said: "Hello". Усередині є лапки, отже, у звичайному рядку їх потрібно екранувати.

import Foundation

let quote = "He said: \"Hello\""
print(quote) // He said: "Hello"

Тут \" — це одна лапка в результаті.

Зворотний слеш всередині рядка: \\

Дуже часта історія — шляхи до файлів, особливо якщо ви бачили Windows-формат, регулярні вирази, до яких ми ще дістанемося пізніше, або просто текст, де слеш — це символ, а не команда.

import Foundation

let path = "C:\\Temp\\new\\file.txt"
print(path) // C:\Temp\new\file.txt

Зверніть увагу: у коді \\, а в результаті друкується один \.

3. Керувальні символи: перенесення і табуляція

До цього ми екранували символи, які заважають синтаксису. Але \n і \t — це інша історія: це символи, які керують форматуванням тексту. Вони не просто друкуються як \ і літера, а справді змінюють вигляд виводу.

Важливо: print() сам по собі додає перенесення рядка в кінці виводу. Але \n — це перенесення рядка всередині самого рядка. Тобто ви можете одним print() вивести кілька рядків.

Перенесення рядка: \n

import Foundation

let report = "Імʼя: Alice\nОцінка: 42"
print(report)
// Імʼя: Alice
// Оцінка: 42

Тут \n робить перенесення прямо всередині значення String.

Табуляція: \t

Табуляція корисна, коли ви хочете візуально вирівняти стовпчики. Так, це не Excel, але для консольних звітів — цілком доречно.

import Foundation

let table = "Товар\tЦіна\nЧай\t3\nТістечко\t5"
print(table)
// Товар   Ціна
// Чай     3
// Тістечко        5

Із табуляцією є нюанс: візуальна ширина залежить від того, де саме ви виводите текст — в IDE, терміналі чи веб-IDE. Але сама ідея незмінна: \t — це «перестрибни на наступну таб-позицію».

4. Багаторядкові рядки: """ ... """

Досі ми робили багаторядковий вивід через \n. Це працює, але швидко стає незручним: рядок перетворюється на «смугу перешкод» зі слешів і літер. Для випадків, коли текст природно багаторядковий — наприклад, довідка, лист або шаблон повідомлення, — у Swift є багаторядковий рядковий літерал.

Він виглядає так: """ відкриває, """ закриває. Усередині можна писати текст «як у звичайному документі», з перенесеннями рядків.

import Foundation

let helpText = """
Ласкаво просимо до TextBuddy!

Команди:
1) help  - показати цю довідку
2) exit  - вийти із застосунку
"""
print(helpText)
// Ласкаво просимо до TextBuddy!
//
// Команди:
// 1) help  - показати цю довідку
// 2) exit  - вийти із застосунку

Що важливо зрозуміти про """ ... """

У багаторядковому рядку перенесення зберігаються. Тобто ви бачите текст у коді майже так само, як він виглядатиме під час друку. Це різко підвищує читабельність і ще зменшує шанс помилитися на одному \n.

Є тонкий момент: відступи всередині багаторядкового літерала можуть «переїхати» в результат, якщо ви зробите їх частиною тексту. Тому тут варто бути уважним: якщо ви хочете гарного форматування в коді й водночас чистого виводу, стежте, які саме пробіли потрапляють усередину рядка.

5. Raw-рядки: ідея «пиши як є»

Іноді ви хочете, щоб рядок сприймався максимально буквально: без перетворення \n на перенесення рядка, без подвоєння слешів і без зайвої магії. Для цього в Swift є raw-рядки (сирі рядки). Їхня ідея дуже проста: навколо рядка додається #, і тоді escape-послідовності в більшості випадків перестають бути магією.

Відразу чесно: вам не потрібно сьогодні запам’ятовувати весь синтаксис raw-рядків. Наша мета — зрозуміти, навіщо вони існують і в яких ситуаціях можуть позбавити вас лісу \\.

Приклад: шлях із зворотними слешами без \\

Порівняйте два варіанти: звичайний рядок і raw-рядок.

import Foundation

let normalPath = "C:\\Temp\\new\\file.txt"
let rawPath = #"C:\Temp\new\file.txt"#

print(normalPath) // C:\Temp\new\file.txt
print(rawPath)    // C:\Temp\new\file.txt

У raw-рядку ми написали шлях «як є», і це читається значно приємніше. Мозку не потрібно подумки «згортати» пари слешів.

Приклад: показати символи \n буквально

Це дуже наочний приклад того, навіщо raw-рядок узагалі потрібен. У звичайному рядку \n стане перенесенням. У raw-рядку це будуть два символи: слеш і n.

import Foundation

let normal = "Line1\nLine2"
let raw = #"Line1\nLine2"#

print(normal)
// Line1
// Line2

print(raw) // Line1\nLine2

Це буває корисно, коли ви друкуєте підказки, документацію, приклади коду, фрагменти конфігурації — усе, де важливо показати саме \n, \t, \ тощо як текст.

6. Приклад: довідка для «TextBuddy»

Тепер зберемо невеликий код, який виглядає як частина нашого навчального консольного застосунку. Ми поки що не робимо повноцінного розбору команд — це окрема тема, — але вже зараз хочемо красиво виводити довідку й пояснювати користувачеві формат введення. Саме тут рядкові літерали вирішують половину задачі UX: застосунок стає привітнішим, а не таким, що каже: «Введіть щось кудись — а далі здогадуйтеся самі».

Нижче — приклад top-level коду, який друкує привітання, підказку і демонструє, як писати команду з лапками.

import Foundation

let appName = "TextBuddy"

let help = """
Ласкаво просимо до \(appName)!

Спробуйте команди:
  help            - показати цю довідку
  exit            - вийти із застосунку

Приклад із лапками:
  add "Купити молоко"
"""

print(help)
// Ласкаво просимо до TextBuddy!
//
// Спробуйте команди:
//   help            - показати цю довідку
//   exit            - вийти із застосунку
//
// Приклад із лапками:
//   add "Купити молоко"

Зверніть увагу на дві речі.

Перша — багаторядковий літерал робить довідку читабельною прямо в коді. Це важливо не лише для користувача, а й для вас через тиждень, коли ви забудете формат.

Друга — усередині довідки ми спокійно показуємо лапки навколо "Купити молоко". Оскільки це багаторядковий рядок, лапки всередині його не ламають. Ламають його лише лапки того самого типу, якими ви відкрили рядок. Тут відкривні лапки — потрійні, а всередині — звичайні, тож усе працює нормально.

А от якщо ви захочете записати такий рядок в один рядок звичайним літералом, доведеться екранувати:

import Foundation

let example = "Приклад: add \"Купити молоко\""
print(example) // Приклад: add "Купити молоко"

7. Типові помилки під час роботи з рядковими літералами

Помилка №1: забули екранувати лапку всередині звичайного рядка.
Дуже класична ситуація: ви пишете let s = "He said: "Hi"" , і компілятор починає сваритися так, ніби ви намагалися прочитати заклинання стародавньою мовою. Причина проста: друга лапка закрила рядок. У звичайному літералі лапку всередині потрібно писати як \", або, якщо текст великий, перейти на багаторядковий літерал.

Помилка №2: написали один \ і чекали, що він стане символом слеша.
У Swift, як і в багатьох мовах, \ — це спосіб увімкнути «магію». Якщо вам потрібен буквальний слеш, у звичайному рядку майже завжди потрібно \\. Якщо слешів багато — шляхи, шаблони, приклади коду, — розумно хоча б розглянути raw-рядок, щоб не перетворювати вихідний код на «паркан» зі зворотних слешів.

Помилка №3: очікували, що \n надрукує два символи \ і n.
У звичайному рядку \n — це перенесення рядка. Якщо вам потрібно показати \n як текст, наприклад у підказці «використайте \n для перенесення», то raw-рядок на кшталт #"\n"# часто розв’язує питання найпростішим способом: без додаткового екранування і без зайвих пояснень компілятору.

Помилка №4: багаторядковий рядок раптом виводить «зайві пробіли» або порожні рядки.
Багаторядковий літерал чесно зберігає те, що ви написали: перенесення рядків, пробіли, порожні рядки. Іноді це чудово, а іноді ви випадково залишили порожній рядок у кінці або зробили відступ, який став частиною тексту. Лікується не магією, а уважністю: дивіться на вміст """ ... """ як на реальний вивід, а не як на «оформлення коду».

Помилка №5: спроба вивчити raw-рядки «до останньої решітки» занадто рано.
Raw-рядки — корисний інструмент, але вони не потрібні в кожному проєкті. Якщо ви ловите себе на думці «я зараз хвилин 20 підбиратиму, скільки треба #», зупиніться й запитайте себе: може, звичайне екранування \\ і \" тут простіше й зрозуміліше? Raw-рядки варто сприймати як зручну опцію, коли рядок справді перевантажений зворотними слешами або вам потрібне буквальне представлення спецпослідовностей.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ