Fork me on GitHub

字符串

Some contents of this translation may be outdated.
Several major changes were applied to the original lesson since the last update.

字符串、字符列表、字素(Graphemes) 和字码点(Codepoints)。

目录

字符串

Elixir 字符串就是字节序列,我们来看一个例子:

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

NOTE: 使用 << >> 是告诉编译器这个符号里面的内容是字节。

字符列表

在 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 模块要用到它。

字素和字码点

字码点(Codepoint)就是一个或者多个字节表示的 Unicode 字符(根据 UTF-8 编码方式,每个字码点会有长度不同)。ASCII 码之外的字符一般都会由多个字节表示,比如带有波浪线或者声调的拉丁字符 (á, ñ, è) 一般都是两个字节表示的。而亚洲语言的字符一般都是三个或者四个字节。字素(Graphemes)就是一个字符的表示,通常由多个字码点组成。

String 模块已经提供了两个方法来获取这两种方式的值:graphemes/1codepoints/1。我们来看一下:

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

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

iex> String.graphemes string
["á"]

字符串函数

这个部分我们看一下 String 模块最常用的一些函数。本课程只会介绍其中的一部分,如果要了解所有的函数,请参考官方 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,反之亦然。

那么,怎么才能用 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,首先我们会检查接受的参数是否为 binaries,这是 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,这个错误就是告诉我们模块中没有接受两个非字符串的函数。这正是我们期望的结果:只接受字符串作为参数,其他都不允许。



分享本页面