Do you want to pick up from where you left of?
Take me there

Строковые метки

Создание и использование строковых меток.

Обзор строковых меток

Elixir предоставляет альтернативный синтаксис для представления и работы с литералами.

Строковая метка начинается с тильды ~, за которой следует идентификатор и пара разделителей. До версии Elixir 1.15 идентификатор должен был быть однобуквенным. Начиная с версии 1.15, идентификатор может быть строкой из нескольких прописных букв.

Ядро Elixir уже включает в себя несколько встроенных строковых меток, однако возможно создавать собственные для расширения возможностей языка.

Список доступных строковых меток включает:

Список доступных разделителей:

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

Строковые метки ~c и ~C создают списки символов. Например:

iex> ~c/2 + 7 = #{2 + 7}/
'2 + 7 = 9'

iex> ~C/2 + 7 = #{2 + 7}/
'2 + 7 = \#{2 + 7}'

Видно, что строчная ~c интерполирует вычисление, а прописная ~C — нет. Далее мы увидим, что во всех встроенных строковых метках встречается такое разделение на строчные и прописные.

Регулярные выражения

Строковые метки ~r и ~R используются для представления регулярных выражений. Мы можем создавать их для использования на лету, либо для применения функций Regex. Например:

iex> re = ~r/elixir/
~r/elixir/

iex> "Elixir" =~ re
false

iex> "elixir" =~ re
true

Как мы видим, в первом тесте на равенство слово Elixir не соответствует регулярному выражению. Дело в том, что оно начинается с заглавной буквы. Elixir поддерживает регулярные выражения PCRE (Perl Compatible Regular Expressions), поэтому мы можем добавить i в конец нашей строковой метки, чтобы отключить регистрозависимость.

iex> re = ~r/elixir/i
~r/elixir/i

iex> "Elixir" =~ re
true

iex> "elixir" =~ re
true

Также Elixir поддерживает Regex API, основанный на библиотеке регулярных выражений из Erlang. Попробуем воспользоваться Regex.split/2 на строковой метке регулярного выражения:

iex> string = "100_000_000"
"100_000_000"

iex> Regex.split(~r/_/, string)
["100", "000", "000"]

Как мы видим, благодаря строковой метке ~r/_/ выражение "100_000_000" разделилось на части по символу подчёркивания. Функция Regex.split возвращает список.

Строка

Строковые метки ~s и ~S используются для создания строк. Например:

iex> ~s/the cat in the hat on the mat/
"the cat in the hat on the mat"

iex> ~S/the cat in the hat on the mat/
"the cat in the hat on the mat"

Но в чём разница? Отличие такое же, как в строковых метках списка символов, которые мы уже рассмотрели ранее — интерполяция и экранирование. Посмотрим на ещё один пример:

iex> ~s/welcome to elixir #{String.downcase "SCHOOL"}/
"welcome to elixir school"

iex> ~S/welcome to elixir #{String.downcase "SCHOOL"}/
"welcome to elixir \#{String.downcase \"SCHOOL\"}"

Список слов

Строковая метка списка слов иногда может оказаться весьма полезной. Эта возможность упростит код и сэкономит время. Возьмём простой пример:

iex> ~w/i love elixir school/
["i", "love", "elixir", "school"]

iex> ~W/i love elixir school/
["i", "love", "elixir", "school"]

Всё, что написано между разделителями, разбивается по пробелу и сохраняется в список. Однако, с виду между этими примерами нет разницы. Она вновь заключается в интерполяции и экранировании. Посмотрим на следующий пример:

iex> ~w/i love #{'e'}lixir school/
["i", "love", "elixir", "school"]

iex> ~W/i love #{'e'}lixir school/
["i", "love", "\#{'e'}lixir", "school"]

NaiveDateTime

NaiveDateTime используется для быстрого создания структуры, представляющей собой DateTime без часового пояса.

Как правило, стоит избегать создания NaiveDateTime напрямую. Однако это может пригодиться для сопоставления с образцом. Например:

iex> NaiveDateTime.from_iso8601("2015-01-23 23:50:07") == {:ok, ~N[2015-01-23 23:50:07]}

DateTime

DateTime может быть полезен для быстрого создания структуры для представления DateTime с временной зоной UTC. Поскольку он находится в UTC, а ваша строка может представлять другую временную зону, возвращается третий элемент, который представляет смещение в секундах.

Например:

iex> DateTime.from_iso8601("2015-01-23 23:50:07Z") == {:ok, ~U[2015-01-23 23:50:07Z], 0}
iex> DateTime.from_iso8601("2015-01-23 23:50:07-0600") == {:ok, ~U[2015-01-24 05:50:07Z], -21600}

Создание строковых меток

Одной из целей разработки языка Elixir было создать гибкий и расширяемый язык программирования. Потому неудивительно, что мы можем создавать свои строковые метки. В этом примере мы создадим строковую метку, которая превращает все символы строки в заглавные. Так как в ядре Elixir уже есть функция (String.upcase/1), то сделаем нашу строковую метку на её основе.


iex> defmodule MySigils do
...>   def sigil_p(string, []), do: String.upcase(string)
...> end

iex> import MySigils
MySigils

iex> ~p/elixir school/
"ELIXIR SCHOOL"

Для начала объявим модуль с именем MySigils и внутри него создадим функцию sigil_p. Мы используем ~p, потому что она не занята в пространстве строковых меток. _p означает, что мы хотим использовать символ p после тильды. Функция должна принимать два аргумента: вводимое значение и список.

Многосимвольные строковые метки

В Elixir 1.15 и выше идентификаторы строковых меток могут быть последовательностью прописных символов. Это может быть полезно, чтобы уточнить назначение строковой метки, предоставляя больше контекста, чем один символ.

Следуя структуре предыдущего примера, мы можем определить строковую метку ~REV, которая переворачивает строку.


iex> defmodule MySigils do
...>   def sigil_REV(string, []), do: String.reverse(string)
...> end

iex> import MySigils
MySigils

iex> ~REV<foobar>
"raboof"

Обратите внимание, что для многосимвольных строковых меток все символы должны быть прописными. Функции строковых меток, такие как sigil_rev или sigil_Rev, вызовут SyntaxError при выполнении.

Caught a mistake or want to contribute to the lesson? Edit this lesson on GitHub!