Зачем строкам столько методов
В реальных программах со строками почти никогда не работают посимвольно. Обычно нужно спросить: «начинается ли имя файла с этого префикса», «есть ли в тексте слово-стоп-фраза», «уберём лишние пробелы, которые пользователь случайно вставил в поле ввода», «разобьём фразу на слова и снова соберём её по-другому». Для всего этого в String уже есть готовые методы — их не нужно писать вручную через индексы и циклы.
Поиск и проверка: contains, hasPrefix, hasSuffix
contains отвечает на вопрос «есть ли такой кусок текста где-нибудь внутри», а hasPrefix и hasSuffix — «начинается» и «заканчивается» ли строка на заданный фрагмент. Все три метода возвращают Bool.
let fileName = "report_final.pdf"
print(fileName.hasPrefix("report")) // true
print(fileName.hasSuffix(".pdf")) // true
print(fileName.contains("final")) // true
print(fileName.contains("draft")) // false
Обратите внимание: все три метода чувствительны к регистру. "Report".hasPrefix("report") вернёт false, потому что заглавная R и строчная r — разные символы.
Замена: replacingOccurrences(of:with:)
Когда нужно не найти фрагмент, а заменить его на другой, используют replacingOccurrences(of:with:). Метод заменяет все вхождения искомого текста и возвращает новую строку — исходная строка при этом не меняется, потому что String в Swift — тип значения.
let message = "Привет, гость! Гость, добро пожаловать."
let fixed = message.replacingOccurrences(of: "Гость", with: "Друг")
print(fixed) // "Привет, гость! Друг, добро пожаловать."
Заменилось только слово с заглавной буквы «Гость», потому что второе слово в тексте пишется со строчной «гость» — метод ищет точное совпадение регистра.
Разбор и сборка: split и joined
split(separator:) делает обратное объединению — разрезает строку по разделителю на части. Результат — набор кусочков текста (сам тип этого набора и его методы подробно разберём позже, когда дойдём до коллекций; пока достаточно знать, что это упорядоченный список частей строки).
let csvLine = "Аня,19,Ташкент"
let parts = csvLine.split(separator: ",")
print(parts) // ["Аня", "19", "Ташкент"]
Обратная операция — joined(separator:): она склеивает части обратно в одну строку через заданный разделитель.
let rebuilt = parts.joined(separator: " | ")
print(rebuilt) // "Аня | 19 | Ташкент"
По умолчанию split(separator:) пропускает пустые части, если разделители встретились подряд: "a,,b".split(separator: ",") даст всего два элемента, "a" и "b", а не три с пустой строкой между ними.
Регистр: uppercased, lowercased, capitalized
uppercased() и lowercased() переводят все буквы строки в верхний или нижний регистр, а capitalized делает заглавной первую букву каждого слова.
let city = "ташкент"
print(city.uppercased()) // "ТАШКЕНТ"
print(city.capitalized) // "Ташкент"
print("SWIFT LANG".lowercased()) // "swift lang"
Так как эти операции — обычные методы и свойство, они не меняют исходную переменную, а возвращают новую строку. Если результат нужен и дальше, его надо сохранить в переменную или константу.
Обрезка пробелов: trimmingCharacters
Пользователи часто оставляют случайные пробелы в начале и в конце введённого текста. Убрать их помогает trimmingCharacters(in: .whitespaces) — метод удаляет пробельные символы только по краям строки, внутри текста ничего не трогая.
let typed = " Ташкент "
let clean = typed.trimmingCharacters(in: .whitespaces)
print("[\(clean)]") // "[Ташкент]"
Многострочные строки
Когда текст занимает несколько строк — например, письмо или блок инструкции — используют литерал в тройных кавычках. Он начинается и заканчивается тремя двойными кавычками на отдельных строках.
let letter = """
Здравствуйте!
Спасибо, что прошли этот урок.
До встречи на следующем.
"""
print(letter)
Здесь важно правило отступа: Swift ориентируется на отступ закрывающих трёх кавычек и убирает точно такой же отступ у каждой строки текста. Поэтому закрывающие кавычки принято ставить на том же уровне отступа, что и открывающие — тогда лишние пробелы слева не попадут в саму строку. Внутри такого литерала можно свободно использовать одинарные кавычки и переносы строк без экранирования.
Сравнение строк: == сравнивает содержимое
В некоторых языках оператор равенства для текста сравнивает, лежат ли две переменные по одному и тому же адресу в памяти. В Swift String — тип значения, и == у строк сравнивает именно содержимое, символ за символом, а не то, как строка была получена.
let a = "Swift"
let b = "Sw" + "ift"
print(a == b) // true — важно только содержимое
Даже если одна строка была введена напрямую, а другая собрана из кусочков через + или joined, результат сравнения зависит только от итогового текста.
Кратко: строка и число
String(число) превращает число в строку — это работает всегда и без сюрпризов.
let score = 97
let scoreText = String(score)
print("Результат: " + scoreText) // "Результат: 97"
Обратное преобразование — «превратить текст в число» — устроено сложнее: не любой текст является числом (в "abc" его нет), поэтому Swift возвращает здесь особое значение, которое умеет сообщать о неудаче. Разбираться с ним подробно будем в следующем уроке.
Частые ошибки
- Забыть, что
hasPrefix,hasSuffixиcontainsчувствительны к регистру, и удивляться, почему очевидное совпадение не находится. - Ждать, что
replacingOccurrences,uppercasedилиtrimmingCharactersизменят исходную переменную — они возвращают новую строку, результат нужно сохранить самому. - Считать, что
split(separator:)сразу даёт готовую строку — на самом деле это набор частей, и для новой строки его нужно собрать черезjoined(separator:). - Ставить закрывающие тройные кавычки многострочного литерала с другим отступом, чем у текста, — тогда в строку попадают лишние пробелы или, наоборот, обрезаются нужные символы.
- Пытаться сравнивать строки через
===по аналогии со ссылочными типами — дляStringдостаточно и правильно использовать обычный==.
Резюме
contains,hasPrefix,hasSuffix— проверки на вхождение, начало и конец строки, возвращаютBool.replacingOccurrences(of:with:)заменяет все вхождения фрагмента и возвращает новую строку.split(separator:)разбирает строку на части,joined(separator:)склеивает части обратно через разделитель.uppercased(),lowercased(),capitalizedменяют регистр букв.trimmingCharacters(in: .whitespaces)убирает пробелы по краям строки.- Литерал в тройных кавычках хранит многострочный текст; отступ определяется по закрывающим кавычкам.
==у строк сравнивает содержимое, а не то, как строка была построена.String(число)надёжно превращает число в текст; обратное преобразование может не получиться и требует особого подхода, который разберём дальше.
Проверьте себя
3 вопроса
Нормализация введённого текста
Пользователи часто вводят текст с лишними пробелами по краям и в произвольном регистре. Напишите функцию normalizeText(_:), которая принимает строку и возвращает новую строку: без пробелов по краям и полностью в нижнем регистре.
Например, для " Hello World " функция должна вернуть "hello world".
Пересборка списка через разделитель
Есть строка, где слова разделены пробелами (одним или несколькими подряд). Напишите функцию reformatList(_:separator:), которая разбивает текст на слова и снова собирает их в одну строку, но уже через переданный разделитель separator.
Например, для текста "apple banana cherry" и разделителя "-" функция должна вернуть "apple-banana-cherry".