🎯 Kotlin

String-Methoden – Vollständige Anleitung in Kotlin: Eine ausführliche Anleitung

Что это такое и зачем? (аналогия из реальной жизни)

Представьте, что вы получили длинное письмо от друга. Что вы можете с ним сделать? Вы можете:

  • Посчитать, сколько в нём слов
  • Найти, встречается ли в нём слово «привет»
  • Заменить одно слово на другое
  • Разделить письмо на отдельные предложения
  • Убрать лишние пробелы в начале и конце
  • Сделать все буквы заглавными или маленькими
  • Проверить, не пустое ли письмо

В программировании строки — это точно такие же «письма», только хранятся они в памяти компьютера. И для работы с ними существуют специальные инструменты — методы строк. Это как набор ножниц, клея, линеек и маркеров, которые помогают вам обрабатывать текст.

Важно: Строки в Kotlin — это неизменяемые (immutable) объекты. Это значит, что когда вы вызываете метод, вы не меняете исходную строку, а создаёте новую. Представьте, что вы делаете ксерокопию письма и работаете уже с копией.

Зачем это нужно? Представьте, что вы пишете программу для регистрации пользователей. Вам нужно:

  • Убрать лишние пробелы из имени (чтобы «Анна » превратилось в «Анна»)
  • Проверить, что email содержит символ «@»
  • Сделать первую букву имени заглавной
  • Заменить в тексте все нецензурные слова на звёздочки

Без методов строк вам пришлось бы писать десятки строк кода вручную. С ними — одна строчка.

Теория: как это работает изнутри

Давайте заглянем «под капот» и поймём, как устроены строки в Kotlin.

Строка — это массив символов

Внутри компьютера строка — это просто последовательность символов (букв, цифр, знаков препинания), расположенных друг за другом. Каждый символ имеет свой номер — индекс. Первый символ имеет индекс 0, второй — 1, и так далее.

Например, строка «Кот» внутри выглядит так:

// Индексы:  0    1    2
// Символы: 'К'  'о'  'т'
val word = "Кот"
println(word[0]) // Выведет: К
println(word[1]) // Выведет: о
println(word[2]) // Выведет: т

Неизменяемость (иммутабельность)

Когда вы вызываете метод toUpperCase(), Kotlin не меняет исходную строку. Вместо этого он создаёт новую строку в памяти, применяет к ней изменения, и возвращает её вам. Исходная строка остаётся нетронутой.

val original = "Привет"
val changed = original.toUpperCase() // Создаётся НОВАЯ строка "ПРИВЕТ"
println(original) // "Привет" — исходная не изменилась!
println(changed)  // "ПРИВЕТ" — новая строка
Почему это важно? Представьте, что у вас есть важный документ. Вы делаете его копию и рисуете на копии. Оригинал остаётся в сохранности. Так и со строками — вы всегда можете вернуться к исходному значению.

Строковый пул (String Pool)

Kotlin (как и Java) использует специальную область памяти — строковый пул. Когда вы создаёте строку с помощью кавычек, Kotlin сначала проверяет: а нет ли уже такой строки в пуле? Если есть — он просто даёт вам ссылку на неё. Это экономит память.

val a = "Привет"
val b = "Привет"
// a и b ссылаются на ОДИН И ТОТ ЖЕ объект в памяти!
println(a === b) // true — это одна и та же ссылка

Кодировка: как хранятся символы

В Kotlin строки хранятся в кодировке UTF-16. Это значит, что каждый символ занимает 2 байта (или 4 для редких символов). Благодаря этому вы можете работать с любыми языками мира: русским, китайским, арабским — без проблем.

Синтаксис в Kotlin: все формы и варианты

Давайте разберём все основные методы строк. Я сгруппировал их по категориям, чтобы было легче запомнить.

1. Проверка и сравнение

Метод Что делает Пример Результат
isEmpty() Проверяет, пустая ли строка (длина = 0) "".isEmpty() true
isNotEmpty() Проверяет, не пустая ли строка "Кот".isNotEmpty() true
isBlank() Проверяет, пустая ли строка или состоит только из пробелов " ".isBlank() true
equals(other) Сравнивает строки по содержимому "Кот".equals("Кот") true
== То же самое, что equals (в Kotlin) "Кот" == "Кот" true

2. Поиск и проверка содержимого

Метод Что делает Пример Результат
contains("текст") Проверяет, содержит ли строка указанный текст "Привет".contains("иве") true
startsWith("Пре") Проверяет, начинается ли строка с указанного текста "Прекрасный".startsWith("Пре") true
endsWith("конец") Проверяет, заканчивается ли строка указанным текстом "Это конец".endsWith("конец") true
indexOf("символ") Находит индекс первого вхождения текста (или -1, если не найдено) "Котёнок".indexOf("тё") 2
lastIndexOf("о") Находит индекс последнего вхождения "Молоко".lastIndexOf("о") 4

3. Изменение регистра

Метод Что делает Пример Результат
toUpperCase() Превращает все буквы в заглавные "кот".toUpperCase() "КОТ"
toLowerCase() Превращает все буквы в строчные "КОТ".toLowerCase() "кот"
capitalize() Делает первую букву заглавной (устарел, но работает) "кот".capitalize() "Кот"
decapitalize() Делает первую букву строчной "Кот".decapitalize() "кот"

4. Обрезка и удаление

Метод Что делает Пример Результат
trim() Убирает пробелы в начале и конце " Кот ".trim() "Кот"
trimStart() Убирает пробелы только в начале " Кот".trimStart() "Кот"
trimEnd() Убирает пробелы только в конце "Кот ".trimEnd() "Кот"
removePrefix("Пре") Удаляет указанное начало, если оно есть "Прекрасный".removePrefix("Пре") "красный"
removeSuffix("конец") Удаляет указанный конец, если он есть "Это конец".removeSuffix(" конец") "Это"

5. Замена и разделение

Метод Что делает Пример Результат
replace("старое", "новое") Заменяет все вхождения одного текста на другой "кот кот".replace("кот", "пёс") "пёс пёс"
replaceFirst("кот", "пёс") Заменяет только первое вхождение "кот кот".replaceFirst("кот", "пёс") "пёс кот"
split("разделитель") Разделяет строку на части по указанному разделителю "яблоко,груша,банан".split(",") ["яблоко", "груша", "банан"]

6. Извлечение части строки

Метод Что делает Пример Результат
substring(начало, конец) Извлекает часть строки от индекса «начало» до «конец» (не включая конец) "Привет".substring(0, 4) "Прив"
take(3) Берёт первые N символов "Привет".take(3) "При"
takeLast(3) Берёт последние N символов "Привет".takeLast(3) "вет"
drop(3) Удаляет первые N символов, возвращает остаток "Привет".drop(3) "вет"
dropLast(3) Удаляет последние N символов "Привет".dropLast(3) "При"

7. Дополнительные полезные методы

Метод Что делает Пример Результат
length Возвращает длину строки (количество символов) "Кот".length 3
reversed() Переворачивает строку задом наперёд "Кот".reversed() "тоК"
repeat(3) Повторяет строку указанное количество раз "Ха".repeat(3) "ХаХаХа"
padStart(10, '*') Дополняет строку слева до указанной длины "Кот".padStart(10, '*') "*******Кот"
padEnd(10, '*') Дополняет строку справа до указанной длины "Кот".padEnd(10, '*') "Кот*******"

Примеры кода — от простого к сложному

Пример 1: Приветствие пользователя (базовые методы)

fun main() {
    // Представьте, что пользователь ввёл своё имя с лишними пробелами
    val userInput = "  анна  "
    
    // Убираем пробелы в начале и конце
    val cleanedName = userInput.trim()
    
    // Делаем первую букву заглавной, остальные — маленькими
    val formattedName = cleanedName.capitalize()
    
    // Выводим приветствие
    println("Привет, $formattedName!") // Выведет: Привет, Анна!
    
    // Проверяем, что исходная строка не изменилась
    println("Исходная строка: '$userInput'") // Выведет: '  анна  '
}

Пример 2: Проверка пароля (методы проверки)

fun main() {
    val password = "Secret123"
    
    // Проверяем длину пароля
    if (password.length < 8) {
        println("Пароль слишком короткий!")
    }
    
    // Проверяем, содержит ли пароль цифры
    val hasDigit = password.any { it.isDigit() }
    if (!hasDigit) {
        println("Пароль должен содержать хотя бы одну цифру!")
    }
    
    // Проверяем, содержит ли пароль заглавные буквы
    val hasUpperCase = password.any { it.isUpperCase() }
    if (!hasUpperCase) {
        println("Пароль должен содержать хотя бы одну заглавную букву!")
    }
    
    // Если все проверки пройдены
    if (password.length >= 8 && hasDigit && hasUpperCase) {
        println("Пароль надёжный!")
    }
}

Пример 3: Обработка email-адреса

fun main() {
    val email = "  User@Example.COM  "
    
    // 1. Убираем пробелы
    val trimmed = email.trim()
    
    // 2. Проверяем, есть ли символ '@'
    if (!trimmed.contains("@")) {
        println("Ошибка: email должен содержать @")
        return
    }
    
    // 3. Разделяем email на имя пользователя и домен
    val parts = trimmed.split("@")
    val username = parts[0]
    val domain = parts[1]
    
    // 4. Приводим домен к нижнему регистру (обычно так делают)
    val normalizedDomain = domain.toLowerCase()
    
    // 5. Собираем обратно
    val normalizedEmail = "$username@$normalizedDomain"
    
    println("Исходный email: $email")
    println("Нормализованный: $normalizedEmail")
    // Выведет: Нормализованный: User@example.com
}

Пример 4: Цензура текста (замена слов)

fun main() {
    val badWords = listOf("дурак", "идиот", "плохой")
    val text = "Ты дурак, если думаешь, что это плохой фильм!"
    
    var censoredText = text
    
    // Проходим по всем плохим словам и заменяем их на звёздочки
    for (word in badWords) {
        // Создаём строку из звёздочек той же длины
        val stars = "*".repeat(word.length)
        censoredText = censoredText.replace(word, stars)
    }
    
    println("Исходный текст: $text")
    println("После цензуры: $censoredText")
    // Выведет: После цензуры: Ты *****, если думаешь, что это ****** фильм!
}

Пример 5: Анализ текста (статистика)

fun main() {
    val text = "Кот и собака дружат. Кот любит молоко. Собака любит кости."
    
    // 1. Разделяем текст на слова
    val words = text.split(" ", ".", "!") // Разделяем по пробелам и знакам препинания
    println("Всего слов: ${words.size}")
    
    // 2. Считаем, сколько раз встречается слово "Кот"
    val catCount = words.count { it == "Кот" || it == "кот" }
    println("Слово 'Кот' встречается $catCount раз(а)")
    
    // 3. Находим самое длинное слово
    val longestWord = words.maxByOrNull { it.length }
    println("Самое длинное слово: '$longestWord' (${longestWord?.length} букв)")
    
    // 4. Переворачиваем каждое слово
    val reversedWords = words.map { it.reversed() }
    println("Слова задом наперёд: $reversedWords")
}

Пример 6: Форматирование номера телефона

fun main() {
    // Представьте, что пользователь ввёл номер телефона без форматирования
    val rawPhone = "1234567890"
    
    // Проверяем, что номер состоит только из цифр
    if (!rawPhone.all { it.isDigit() }) {
        println("Ошибка: номер должен содержать только цифры!")
        return
    }
    
    // Проверяем длину
    if (rawPhone.length != 10) {
        println("Ошибка: номер должен содержать 10 цифр!")
        return
    }
    
    // Форматируем: (123) 456-7890
    val areaCode = rawPhone.take(3)
    val firstPart = rawPhone.substring(3, 6)
    val secondPart = rawPhone.takeLast(4)
    
    val formattedPhone = "($areaCode) $firstPart-$secondPart"
    
    println("Исходный номер: $rawPhone")
    println("Отформатированный: $formattedPhone")
    // Выведет: Отформатированный: (123) 456-7890
}

Пример 7: Генератор «лесенки» из текста

fun main() {
    val word = "Кот"
    
    // Создаём «лесенку»: сначала одна буква, потом две, потом три...
    println("Строим лесенку из слова '$word':")
    for (i in 1..word.length) {
        // Берём первые i символов
        val part = word.take(i)
        // Дополняем справа точками до длины исходного слова
        val padded = part.padEnd(word.length, '.')
        println(padded)
    }
    
    // Выведет:
    // К..
    // Ко.
    // Кот
}

Пример 8: Проверка, является ли строка палиндромом

fun main() {
    fun isPalindrome(text: String): Boolean {
        // Убираем пробелы и приводим к нижнему регистру
        val cleaned = text.replace(" ", "").toLowerCase()
        // Сравниваем с перевёрнутой версией
        return cleaned == cleaned.reversed()
    }
    
    // Тестируем
    val test1 = "А роза упала на лапу Азора"
    val test2 = "Привет"
    
    println("'$test1' — палиндром? ${isPalindrome(test1)}") // true
    println("'$test2' — палиндром? ${isPalindrome(test2)}") // false
}

Сравнение с Python: чем похоже и чем отличается

Если вы уже знакомы с Python, вам будет легче изучать Kotlin. Давайте сравним основные методы:

Операция Kotlin Python Примечание
Длина строки "кот".length len("кот") В Kotlin это свойство, в Python — функция
Верхний регистр "кот".toUpperCase() "кот".upper() Разные названия методов
Нижний регистр "КОТ".toLowerCase() "КОТ".lower() Разные названия
Удаление пробелов " кот ".trim() " кот ".strip() Разные названия
Разделение "a,b".split(",") "a,b".split(",") Одинаково!
Замена "кот".replace("к", "п") "кот".replace("к", "п") Одинаково!
Проверка начала "кот".startsWith("к") "кот".startswith("к") Разный регистр буквы 'w'
Проверка конца "кот".endsWith("т") "кот".endswith("т") Разный регистр буквы 'w'
Поиск подстроки "кот".indexOf("о") "кот".index("о") В Python — index, в Kotlin — indexOf
Извлечение части "кот".substring(0, 2) "кот"[0:2] В Python — срезы, в Kotlin — метод
Повторение строки "Ха".repeat(3) "Ха" * 3 В Python — оператор, в Kotlin — метод
Главное отличие: В Python строки тоже неизменяемы, но синтаксис более лаконичный (особенно срезы). Kotlin более строгий в типах, но предлагает больше встроенных методов для работы со строками.

Типичные ошибки и подводные камни

Ошибка 1: Забываем, что строки неизменяемы

fun main() {
    var text = "Привет"
    text.toUpperCase() // ОШИБКА: результат не сохранён!
    println(text) // Выведет: "Привет" — строка не изменилась!
    
    // Правильно:
    text = text.toUpperCase()
    println(text) // "ПРИВЕТ"
}

Ошибка 2: Путаем isEmpty() и isBlank()

fun main() {
    val text = "   "
    
    println(text.isEmpty()) // false — строка не пустая, в ней есть пробелы
    println(text.isBlank()) // true — строка состоит только из пробелов
    
    // Если вам нужно проверить, что пользователь что-то ввёл,
    // используйте isBlank(), а не isEmpty()!
}

Ошибка 3: Выход за границы строки

fun main() {
    val text = "Кот"
    
    // println(text[5]) // ОШИБКА! Индекс 5 не существует (максимум 2)
    
    // Безопасный способ — использовать getOrNull
    println(text.getOrNull(5)) // null — ошибки нет
    println(text.getOrNull(5) ?: "Символа нет") // "Символа нет"
}

Ошибка 4: Сравнение строк через === вместо ==

fun main() {
    val a = "Привет"
    val b = String("Привет".toCharArray()) // Создаём новую строку
    
    println(a == b)  // true — сравнивает содержимое
    println(a === b) // false — сравнивает ссылки (разные объекты)
    
    // ВСЕГДА используйте == для сравнения строк!
}

Ошибка 5: Забываем про регистр при поиске

fun main() {
    val text = "Кот и собака"
    
    // Поиск без учёта регистра
    println(text.contains("кот")) // false — потому что "Кот" с большой буквы
    
    // Правильно:
    println(text.toLowerCase().contains("кот")) // true
}

Ошибка 6: Неправильное использование split

fun main() {
    val text = "яблоко,груша,банан"
    
    // Разделяем по запятой
    val fruits = text.split(",")
    println(fruits) // [яблоко, груша, банан]
    
    // ОШИБКА: если разделитель не найден, вернётся список с одним элементом
    val result = text.split(";")
    println(result) // [яблоко,груша,банан] — весь текст как один элемент
}

Лучшие практики и советы профессионалов

1. Используйте цепочки методов (method chaining)

Методы можно вызывать друг за другом. Это делает код компактным и читаемым:

// Плохо: много временных переменных
val input = "  ПРИВЕТ  "
val trimmed = input.trim()
val lower = trimmed.toLowerCase()
val capitalized = lower.capitalize()

// Хорошо: цепочка методов
val result = input.trim().toLowerCase().capitalize()
println(result) // "Привет"

2. Используйте строковые шаблоны вместо конкатенации


                                    
                ← Vorherige
                Dateiarbeit in Kotlin: Eine ausführliche Anleitung
            
            
                                    
                Weiter →
                Methoden für Arrays und Sammlungen in Kotlin: Eine