當前位置: 首頁>>編程示例 >>用法及示例精選 >>正文


Elixir String用法及代碼示例

Elixir語言中 String 相關用法介紹如下。

Elixir 中的字符串是 UTF-8 編碼的二進製文件。

Elixir 中的字符串是一係列 Unicode 字符,通常寫在雙引號字符串之間,例如 "hello""héllò"

如果字符串本身必須有 double-quote,則必須使用反斜杠對雙引號進行轉義,例如:"this is a string with \"double quotes\""

您可以使用 <>/2 運算符連接兩個字符串:

iex> "hello" <> " " <> "world"
"hello world"

插值

Elixir 中的字符串也支持插值。這允許您使用 #{} 語法在字符串中間放置一些值:

iex> name = "joe"
iex> "hello #{name}"
"hello joe"

任何 Elixir 表達式在插值內都是有效的。如果給定字符串,則按原樣插入字符串。如果給出任何其他值,Elixir 將嘗試使用 String.Chars 協議將其轉換為字符串。例如,這允許從插值輸出一個整數:

iex> "2 + 2 = #{2 + 2}"
"2 + 2 = 4"

如果您要插入的值無法轉換為字符串,因為它沒有人工文本表示,則會引發協議錯誤。

轉義字符

除了允許 double-quotes 用反斜杠轉義外,字符串還支持以下轉義字符:

  • \a - 貝爾
  • \b - 退格
  • \t - 水平選項卡
  • \n - 換行(新行)
  • \v - 垂直選項卡
  • \f - 換頁
  • \r - 回車
  • \e - 命令轉義
  • \# - 返回 # 字符本身,跳過插值
  • \xNN - 由十六進製表示的字節 NN
  • \uNNNN - 由 NNNN 表示的 Unicode 代碼點

請注意,通常不建議在 Elixir 字符串中使用 \xNN,因為引入無效的字節序列會使字符串無效。如果您必須通過其十六進製表示來引入字符,最好使用 Unicode 代碼點,例如 \uNNNN 。事實上,在對字符串進行低級操作時,理解 Unicode 碼位是必不可少的,接下來讓我們詳細探討一下。

代碼點和字素簇

此模塊中的函數根據The Unicode Standard, Version 14.0.0 執行。

根據標準,代碼點是單個 Unicode 字符,可以用一個或多個字節表示。

例如,盡管代碼點 "é" 是單個字符,但其底層表示使用兩個字節:

iex> String.length("é")
1
iex> byte_size("é")
2

此外,該模塊還介紹了字素簇的概念(從現在起稱為字素)。字形可以由多個代碼點組成,讀者可以將其視為單個字符。例如,"é" 可以表示為單個“帶尖音符的 e”代碼點,也可以表示為字母 "e" 後跟“組合尖音符”(兩個代碼點):

iex> string = "\u0065\u0301"
iex> byte_size(string)
3
iex> String.length(string)
1
iex> String.codepoints(string)
["e", "́"]
iex> String.graphemes(string)
["é"]

雖然上麵的例子是由兩個字符組成的,但它被用戶認為是一個字符。

字形也可以是被某些語言解釋為一個的兩個字符。例如,某些語言可能會將"ch" 視為單個字符。但是,由於此信息取決於區域設置,因此此模塊不考慮它。

通常,此模塊中的函數依賴於 Unicode 標準,但不包含任何特定於語言環境的行為。關於字素的更多信息可以在Unicode Standard Annex #29 中找到。

要將二進製文件轉換為不同的編碼和 Unicode 規範化機製,請參閱 Erlang 的 :unicode 模塊。

字符串和二進製操作

根據 Unicode 標準,此模塊中的許多函數以線性時間運行,因為它們需要考慮適當的 Unicode 代碼點遍曆整個字符串。

例如,隨著輸入的增長, String.length/1 將花費更長的時間。另一方麵, Kernel.byte_size/1 始終以恒定時間運行(即,無論輸入大小如何)。

這意味著與直接使用二進製文件的更底層操作相比,使用此模塊中的函數通常會產生性能成本:

在許多情況下,可以避免使用 String 模塊以支持二進製函數或模式匹配。例如,假設您有一個字符串 prefix 並且您想從另一個名為 full 的字符串中刪除此前綴。

有人可能會想寫:

iex> take_prefix = fn full, prefix ->
...>   base = String.length(prefix)
...>   String.slice(full, base, String.length(full) - base)
...> end
iex> take_prefix.("Mr. John", "Mr. ")
"John"

盡管上麵的函數有效,但它的性能很差。要計算字符串的長度,我們需要完全遍曆它,所以我們同時遍曆prefixfull字符串,然後將full切片,再次遍曆。

改進它的第一次嘗試可能是使用範圍:

iex> take_prefix = fn full, prefix ->
...>   base = String.length(prefix)
...>   String.slice(full, base..-1)
...> end
iex> take_prefix.("Mr. John", "Mr. ")
"John"

雖然這要好得多(我們不會遍曆 full 兩次),但它仍然可以改進。在這種情況下,由於我們想從字符串中提取子字符串,我們可以使用 Kernel.byte_size/1 Kernel.binary_part/3 ,因為我們不可能在由超過一個字節組成的代碼點的中間進行切片:

iex> take_prefix = fn full, prefix ->
...>   base = byte_size(prefix)
...>   binary_part(full, base, byte_size(full) - base)
...> end
iex> take_prefix.("Mr. John", "Mr. ")
"John"

或者幹脆使用模式匹配:

iex> take_prefix = fn full, prefix ->
...>   base = byte_size(prefix)
...>   <<_::binary-size(base), rest::binary>> = full
...>   rest
...> end
iex> take_prefix.("Mr. John", "Mr. ")
"John"

另一方麵,如果您想根據整數值動態地對字符串進行切片,那麽使用 String.slice/3 是最好的選擇,因為它可以保證我們不會錯誤地將有效代碼點拆分為多個字節。

整數代碼點

盡管代碼點表示為整數,但此模塊將其編碼格式的代碼點表示為字符串。例如:

iex> String.codepoints("olá")
["o", "l", "á"]

有幾種方法可以檢索字符代碼點。可以使用? 構造:

iex> ?o
111

iex> ?á
225

或者也通過模式匹配:

iex> <<aacute::utf8>> = "á"
iex> aacute
225

正如我們在上麵看到的,代碼點可以通過它們的十六進製代碼插入到字符串中:

iex> "ol\u00E1"
"olá"

最後,要將字符串轉換為整數代碼點列表,在 Elixir 中稱為 "charlists",您可以調用 String.to_charlist

iex> String.to_charlist("olá")
[111, 108, 225]

Self-synchronization

UTF-8 編碼是self-synchronizing。這意味著如果遇到格式錯誤的數據(即根據編碼定義不可能的數據),則隻需拒絕一個代碼點。

此模塊依賴此行為來忽略此類無效字符。例如, length/1 將返回正確的結果,即使輸入了無效的代碼點也是如此。

換句話說,該模塊期望在其他地方檢測到無效數據,通常是在從外部源檢索數據時。例如,從數據庫讀取字符串的驅動程序將負責檢查編碼的有效性。 String.chunk/2 可用於將字符串分成有效和無效部分。

編譯二進製模式

此模塊中的許多函數都使用模式。例如, String.split/3 可以在給定模式的情況下將一個字符串拆分為多個字符串。此模式可以是字符串、字符串列表或編譯模式:

iex> String.split("foo bar", " ")
["foo", "bar"]

iex> String.split("foo bar!", [" ", "!"])
["foo", "bar", ""]

iex> pattern = :binary.compile_pattern([" ", "!"])
iex> String.split("foo bar!", pattern)
["foo", "bar", ""]

當一次又一次地完成相同的匹配時,編譯模式很有用。請注意,編譯後的模式不能存儲在模塊屬性中,因為模式是在運行時生成的,並且不會在編譯時存活。

相關用法


注:本文由純淨天空篩選整理自elixir-lang.org大神的英文原創作品 String。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。