Рядки (strings) — це послідовності символів у кодуванні UTF-8. В Elixir рядки закліченні в подвійні лапки та мають багато корисних функцій для маніпуляції.
Основи рядків
Рядки в Elixir — це послідовності знаків, закодовані в UTF-8:
# Прості рядки
name = "Іван"
message = "Привіт, світ!"
# Багаторядкові рядки
text = "Це перший рядок
Це другий рядок
Це третій рядок"
# Спеціальні символи
escaped = "Лінія 1\nЛінія 2\tТабуляція"
quote = "Він сказав \"Привіт!\""
# Довжина рядка (кількість символів)
String.length("Привіт")
# 6
# Визначення порожнього рядка
empty = ""
String.length(empty)
# 0
На відміну від списків символів (char lists), рядки у подвійних лапках — це бінарні значення UTF-8.
Рядки vs побайтові послідовності
В Elixir існує различниця між рядками та побайтовими послідовностями:
# Рядок (string) - подвійні лапки
string = "Hello"
byte_size(string)
# 5
# Список символів (charlist) - одинарні лапки
charlist = 'Hello'
# [72, 101, 108, 108, 111]
# Рядок в UTF-8 займає більше байтів
string_ua = "Привіт"
String.length(string_ua) # 6 символів
byte_size(string_ua) # 12 байтів (2 байти за символ)
# Конвертація
String.to_charlist("Hi")
# [72, 105]
List.to_string([72, 105])
# "Hi"
Інтерполяція
Інтерполяція дозволяє вставляти значення в рядки за допомогою #{}:
name = "Марія"
age = 25
# Проста інтерполяція
greeting = "Привіт, #{name}!"
# "Привіт, Марія!"
# Вирази в інтерполяції
message = "#{name} має #{age} років"
# "Марія має 25 років"
# Математичні операції
result = "Результат: #{5 + 3}"
# "Результат: 8"
# Виклики функцій
text = "Велику літеру: #{String.upcase("hello")}"
# "Велику літеру: HELLO"
# Без інтерполяції
no_interpolate = "Це #{} не буде замінено"
# Помилка! Потрібно значення
Конкатенація та манупуляція
# Конкатенація оператором <>>
hello = "Hello"
world = "World"
result = hello <> " " <> world
# "Hello World"
# Функція String.concat
String.concat(["a", "b", "c"])
# "abc"
# Отримання символу за індексом
String.at("Hello", 0)
# "H"
String.at("Hello", 10)
# nil (індекс поза межами)
# Нарізання рядка
String.slice("Hello World", 0..4)
# "Hello"
String.slice("Hello World", 6..-1)
# "World"
# Заміна
String.replace("Hello World", "World", "Elixir")
# "Hello Elixir"
String.replace("aaa", "a", "b")
# "bbb"
String.replace("aaa", "a", "b", global: false)
# "baa" (тільки перша)
Перетворення регістру
# Великі літери
String.upcase("hello")
# "HELLO"
String.upcase("привіт")
# "ПРИВІТ"
# Малі літери
String.downcase("HELLO")
# "hello"
String.downcase("ПРИВІТ")
# "привіт"
# Перша велика, решта малі
String.capitalize("hELLO")
# "Hello"
# Кожне слово з великої літери
Regex.replace(~r/(\A|\s)(\S)/, "hello world", "\\1\\U\\2")
# "Hello World"
Поділ та з'єднання
# Поділ рядка
String.split("apple,banana,cherry", ",")
# ["apple", "banana", "cherry"]
# Поділ з регулярним виразом
String.split("a1b2c3", ~r/\d/)
# ["a", "b", "c", ""]
# З'єднання списку рядків
Enum.join(["a", "b", "c"], "-")
# "a-b-c"
# Видалення розділювачів на кінцях
String.trim(" hello ")
# "hello"
String.trim_leading(" hello ")
# "hello "
String.trim_trailing(" hello ")
# " hello"
String.trim("123abc123", "123")
# "abc"
Пошук та перевірка
# Перевірка наявності підрядка
String.contains?("Hello World", "World")
# true
# Пошук позиції підрядка
String.myers_difference("kitten", "sitting")
# [eq: "k", del: "itten", ins: "sitting"]
# Перевірка початку/кінця
String.starts_with?("Elixir", "Eli")
# true
String.ends_with?("Elixir", "xir")
# true
# Перевірка, чи рядок лише з букв/цифр
String.match?("123", ~r/^\d+$/)
# true
String.match?("abc123", ~r/^[a-z]+$/)
# false
Регулярні вирази
Для складного пошуку та заміни в рядках використовуються регулярні вирази:
# Обрання за регулярним виразом
Regex.match?(~r/\d+/, "abc123def")
# true
# Отримання матчів
Regex.scan(~r/\d+/, "a1b2c3")
# [["1"], ["2"], ["3"]]
# Заміна за регулярним виразом
Regex.replace(~r/\d/, "a1b2c3", "X")
# "aXbXcX"
# Розділ за регулярним виразом
Regex.split(~r/\s+/, "hello world test")
# ["hello", "world", "test"]
Практичні приклади
# Email валідація
validate_email = fn email ->
Regex.match?(~r/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, email)
end
validate_email.("user@example.com")
# true
# Форматування телефонного номера
format_phone = fn phone ->
phone
|> String.replace(~r/\D/, "")
|> String.slice(0..9)
|> (fn n -> "(#{String.slice(n, 0..2)}) #{String.slice(n, 3..5)}-#{String.slice(n, 6..9)}" end).()
end
format_phone.("1234567890")
# "(123) 456-7890"
# Трансформація: camelCase до snake_case
camel_to_snake = fn str ->
str
|> String.replace(~r/([a-z])([A-Z])/, "\\1_\\2")
|> String.downcase()
end
camel_to_snake.("firstName")
# "first_name"
# Видалення невидимих символів
clean_text = fn text ->
text
|> String.trim()
|> String.replace(~r/\s+/, " ")
end
clean_text.(" hello world ")
# "hello world"
Кодування та символи
# Перетворення в код точки Unicode
String.to_charlist("A")
# [65]
String.codepoints("ABC")
# ["A", "B", "C"]
# Кодування в різні формати
Base.encode64("Hello")
# "SGVsbG8="
Base.decode64("SGVsbG8=")
# {:ok, "Hello"}
# UTF-8 кодування
string = "Привіт"
:unicode.characters_to_binary(string, :utf8)
# <<208, 159, 209, 128, 208, 184, 208, 178, 209, 150, 209, 130>>
Часто використовувані функції String
| Функція | Опис | Приклад |
|---|---|---|
| length/1 | Кількість символів | String.length("Hi") → 2 |
| upcase/1 | Велика літера | String.upcase("hello") → "HELLO" |
| downcase/1 | Мала літера | String.downcase("HELLO") → "hello" |
| trim/1 | Видалити пробіли | String.trim(" hi ") → "hi" |
| split/2 | Поділити рядок | String.split("a,b", ",") → ["a", "b"] |
| replace/3 | Замінити підрядок | String.replace("abc", "a", "x") → "xbc" |
| contains?/2 | Перевірити наявність | String.contains?("hello", "ell") → true |
| slice/2 | Витягти частину | String.slice("hello", 0..1) → "he" |
StringIO для обробки потоків
# Читання з рядка як зіStream
{:ok, pid} = StringIO.open("Hello World")
IO.read(pid, :line)
# "Hello World"
# Запис у рядок
{:ok, pid} = StringIO.open("")
IO.write(pid, "Hello")
IO.write(pid, " ")
IO.write(pid, "World")
StringIO.contents(pid)
# {"Hello World", ""}
# Очистити та заново писати
StringIO.rewind(pid)
IO.write(pid, "New content")
Рядки незмінні в Elixir. Всі операції з ними повертають нові рядки.
Коментарі
Дописати коментар