Fork me on GitHub

Строки

Строки, списки символов, графемы и коды символов.

Содержание

Строки

Строки в Elixir — это не что иное, как последовательность байтов. Взглянем на пример:

iex> string = <<104,101,108,108,111>>
"hello"

ПРИМЕЧАНИЕ: Используя « », мы сообщаем компилятору, что элементы внутри этих символов — это байты.

Списки символов

В языке Elixir есть списки символов, однако строки представлены в виде последовательности байтов. Строки в Elixir заключаются в двойные кавычки, а списки символов — в одинарные.

Но в чём разница? Каждое значение в списке символов — это значение ASCII этого символа. Рассмотрим поглубже:

iex> char_list = 'hello'
'hello'

iex> [hd|tl] = char_list
'hello'

iex> {hd, tl}
{104, 'ello'}

iex> Enum.reduce(char_list, "", fn char, acc -> acc <> to_string(char) <> "," end)
"104,101,108,108,111,"

Программируя на Elixir, мы обычно используем строки, а не списки символов. Поддержка списков символов включена, в основном, для совместимости с некоторыми модулями Erlang.

Графемы и коды символов

Unicode код — это символ Unicode, который представлен одним или более байтами в зависимости от кодировки UTF-8. Символы, не входящие в набор US ASCII всегда кодируются более, чем одним байтом. Например, латинские символы с тильдой или акцентами: á, ñ, è обычно закодированы двумя байтами. Символы из азиатских языков, как правило, закодированы тремя-четырьмя байтами. Графема состоит из нескольких Unicode кодов и выглядит как один символ.

Модуль строки предоставляет два метода для их получения: graphemes/1 и codepoints/1. Взглянем на пример:

iex> string = "\u0061\u0301"
"á"

iex> String.codepoints string
["a", "́"]

iex> String.graphemes string
["á"]

Строковые функции

Рассмотрим некоторые самые важные и полезные функции модуля строки. Этот урок покрывает лишь часть доступных функций. Чтобы ознакомиться с полным списком, можно посетить страницу официальной документации.

length/1

Возвращает количество графем в строке.

iex> String.length "Hello"
5

replace/3

Возвращает новую строку, заменив в исходной строке выбранное выражение на некоторую строку замены.

iex> String.replace("Hello", "e", "a")
"Hallo"

duplicate/2

Возвращает строку, повторённую n раз.

iex> String.duplicate("Oh my ", 3)
"Oh my Oh my Oh my "

split/2

Возвращает список строк, разделённых по выражению.

iex> String.split("Hello World", " ")
["Hello", "World"]

Упражнения

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

Анаграммы

A и B считаются анаграммами, если существует способ перестановки A или B таким образом, чтобы в итоге строки стали равны. Например:

Если мы изменим порядок символов в A, мы можем получить B, и наоборот.

И как мы можем проверить в Elixir, являются ли две строки анаграммами? Простейшее решение — отсортировать графемы в каждой строке по алфавиту и проверить, равны ли списки. Давайте попробуем:

defmodule Anagram do
  def anagrams?(a, b) when is_binary(a) and is_binary(b) do
    sort_string(a) == sort_string(b)
  end

  def sort_string(string) do
    string
    |> String.downcase
    |> String.graphemes
    |> Enum.sort
  end
end

Давайте взглянем на anagrams?/2. Мы проверяем, является ли каждый из параметров бинарными данными. Именно таким образом в Elixir можно проверить, что параметр является строкой.

Дальше мы просто вызываем функцию, сортирующую строку в алфавитном порядке, предварительно переведя строки в нижний регистр и использовав String.graphemes, чтобы получить список графем в строке. Довольно очевидно, не так ли?

Проверим вывод в iex:

iex> Anagram.anagrams?("Hello", "ohell")
true

iex> Anagram.anagrams?("María", "íMara")
true

iex> Anagram.anagrams?(3, 5)
** (FunctionClauseError) no function clause matching in Anagram.anagrams?/2
    iex:2: Anagram.anagrams?(3, 5)

Как вы могли заметить, последний вызов anagrams? завершился с FunctionClauseError. Эта ошибка говорит нам о том, что в нашем модуле нет функции, которая могла бы принимать два небинарных аргумента. И это именно то, что мы хотим — просто принимать две строки и ничего больше.


Поделиться