Строковые метки
Создание и использование строковых меток.
Обзор строковых меток
Elixir предоставляет альтернативный синтаксис для представления и работы с литералами.
Строковая метка начинается с тильды ~
, за которой следует идентификатор и пара разделителей. До версии Elixir 1.15 идентификатор должен был быть однобуквенным. Начиная с версии 1.15, идентификатор может быть строкой из нескольких прописных букв.
Ядро Elixir уже включает в себя несколько встроенных строковых меток, однако возможно создавать собственные для расширения возможностей языка.
Список доступных строковых меток включает:
-
~C
Создаёт список символов без экранирования и интерполяции -
~c
Создаёт список символов с экранированием и интерполяцией -
~R
Создаёт регулярное выражение без экранирования и интерполяции -
~r
Создаёт регулярное выражение с экранированием и интерполяцией -
~S
Создаёт строку без экранирования и интерполяции -
~s
Создаёт строку с экранированием и интерполяцией -
~W
Создаёт список слов без экранирования и интерполяции -
~w
Создаёт список слов с экранированием и интерполяцией -
~N
Создаёт структуруNaiveDateTime
-
~U
Создаёт структуруDateTime
(начиная с Elixir 1.9.0)
Список доступных разделителей:
-
<...>
Пара угловых скобок -
{...}
Пара фигурных скобок -
[...]
Пара квадратных скобок -
(...)
Пара круглых скобок -
|...|
Пара вертикальных черт -
/.../
Пара косых черт -
"..."
Пара двойных кавычек -
'...'
Пара одинарных кавычек
Список символов
Строковые метки ~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!