印记

我们已经知道 Elixir 提供了双引号字符串和单引号 char 列表。但是,这只涵盖了语言中具有文本表示的结构的表面。例如,原子大多是通过:atom表示创建的。

Elixir 的目标之一是可扩展性:开发人员应该能够扩展语言以适应任何特定的领域。计算机科学已经成为如此广泛的领域,一个语言作为其核心的一部分不可能解决许多领域。相反,我们最好的选择是让语言具有可扩展性,因此开发人员,公司和社区可以将语言扩展到相关领域。

在这一章中,我们将探讨 sigils,这是语言提供的用于处理文本表示的机制之一。Sigils 以 tilde(~)字符开头,后面跟着一个字母(标识 sigil),然后是一个分隔符; 可选地,可以在最终定界符后添加修饰符。

常用表达

Elixir 中最常用的sigil ~r是用来创建正则表达式的

# A regular expression that matches strings which contain "foo" or "bar":
iex> regex = ~r/foo|bar/
~r/foo|bar/
iex> "foo" =~ regex
true
iex> "bat" =~ regex
false

Elixir 提供了 Perl 兼容的正则表达式(正则表达式),由PCRE库实现。正则表达式也支持修饰符。例如,i修饰符使正则表达式不区分大小写:

iex> "HELLO" =~ ~r/hello/
false
iex> "HELLO" =~ ~r/hello/i
true

查看Regex模块以获取有关其他修饰符的更多信息以及使用正则表达式支持的操作。

到目前为止,所有示例都用于/划定正则表达式。但是,sigils 支持8种不同的分隔符:

~r/hello/
~r|hello|
~r"hello"
~r'hello'
~r(hello)
~r[hello]
~r{hello}
~r<hello>

支持不同分隔符背后的原因是提供了一种无需转义分隔符即可编写文字的方法。例如,正则表达式的正斜杠类似于~r(^https?://)read可以比~r/^https?:\/\//。同样,如果正则表达式具有正斜杠和捕获组(使用()),则可以选择双引号而不使用括号。

字符串、字符列表和单词列表

除了正则表达式,Elixir 还附带有三个其他标志。

字符串

~s印记被用来生成字符串,如双引号。~s当字符串包含双引号时,sigil 很有用:

iex> ~s(this is a string with "double" quotes, not 'single' ones)
"this is a string with \"double\" quotes, not 'single' ones"

Char 列表

~c印记是用于生成包含单引号字符的列表非常有用:

iex> ~c(this is a char list containing 'single quotes')
'this is a char list containing \'single quotes\''

单词列表

~w印记被用来生成一大堆单词(都只是普通的字符串)。在~wsigil 内部,单词由空白分隔。

iex> ~w(foo bar bat)
["foo", "bar", "bat"]

~w印记还接受csa调节剂(炭列表,字符串和原子,分别地),其指定生成的列表的元素的数据类型:

iex> ~w(foo bar bat)a
[:foo, :bar, :bat]

插入和转义签名

除了小写字母,Elixir 还支持大写字母来处理转义字符和插值。虽然两者~s~S返回字符串,前者允许转义码和内插,而后者则没有:

iex> ~s(String with escape codes \x26 #{"inter" <> "polation"})
"String with escape codes & interpolation"
iex> ~S(String without escape codes \x26 without #{interpolation})
"String without escape codes \\x26 without \#{interpolation}"

以下转义码可用于字符串和字符列表中:

  • \\ - 单个反斜杠
  • \a - 响铃/警报
  • \b - 退格
  • \d - 删除
  • \e - 逃跑(跳出)
  • \f - 形式饲料
  • \n - 新线
  • \r - 回车
  • \s - 空间(空格)
  • \t - 标签
  • \v - 垂直标签
  • \0 - 零字节
  • \xDD- 表示以十六进制表示的单个字节(如\x13
  • \uDDDD\u{D...}- 代表十六进制的 Unicode 代码点(如\u{1F600}

除此之外,双引号字符串中的双引号需要转义\",因此,类似地,单引号 char 列表中的单引号需要被转义为\'。不过,如上所述更改分隔符的风格要好于避开它们。

Sigils 也支持 heredocs,即三倍双引号或单引号作为分隔符:

iex> ~s"""
...> this is
...> a heredoc string
...> """

heredoc sigils 最常见的用例是编写文档时。例如,在文档中编写转义字符很快就会变得很容易出错,因为需要双重转义某些字符:

@doc """
Converts double-quotes to single-quotes.

## Examples

    iex> convert("\\\"foo\\\"")
    "'foo'"

"""
def convert(...)

通过使用~S,这个问题可以完全避免:

@doc ~S"""
Converts double-quotes to single-quotes.

## Examples

    iex> convert("\"foo\"")
    "'foo'"

"""
def convert(...)

自定义标识

正如本章开头所暗示的,Elixir 的信件是可扩展的。实际上,使用sigil ~r/foo/i相当于使用二进制调用sigil_r和 char 列表作为参数进行调用:

iex> sigil_r(<<"foo">>, 'i')
~r"foo"i

我们可以通过以下sigil_r方式访问~rsigil 的文档:

iex> h sigil_r
...

我们还可以通过实施遵循sigil_{identifier}模式的功能来提供我们自己的签名。例如,让我们实现~i返回一个整数的 sigil(使用可选n修饰符使其为负数):

iex> defmodule MySigils do
...>   def sigil_i(string, []), do: String.to_integer(string)
...>   def sigil_i(string, [?n]), do: -String.to_integer(string)
...> end
iex> import MySigils
iex> ~i(13)
13
iex> ~i(42)n
-42

Sigils 也可以用于在宏的帮助下进行编译时工作。例如,Elixir中的正则表达式在编译源代码时被编译成高效的表示形式,因此在运行时跳过这一步。如果您对这个主题感兴趣,我们建议您了解更多关于宏的内容,并了解Kernel模块中的sigil_*信号是如何实现的(函数定义的地方)。