站内seo怎么做,wordpress 小视频,wordpress 页面显示文章,盐城代运营在“基本类型”中#xff0c;我们学习了一些关于字符串的知识#xff0c;并使用 is_binary/1 函数进行检查#xff1a;
iexstring hello hello iexis_binary(string) true
在本章中#xff0c;我们将明确二进制到底是什么、它们与字符串…在“基本类型”中我们学习了一些关于字符串的知识并使用 is_binary/1 函数进行检查
iexstring hello hello iexis_binary(string) true
在本章中我们将明确二进制到底是什么、它们与字符串的关系以及 Elixir 中单引号值“like this”的含义。虽然字符串是计算机语言中最常见的数据类型之一但它们却非常复杂经常被误解。要理解 Elixir 中的字符串我们必须了解 Unicode 和字符编码特别是 UTF-8 编码。
Unicode和码位
为了促进跨多种语言的计算机之间的有意义的通信需要一个标准以便一台机器上的 1 和 0 在传输到另一台机器时具有相同的含义。Unicode 标准充当了我们所知道的几乎所有字符的官方注册表这包括来自古典和历史文本的字符、表情符号以及格式和控制字符。
Unicode 将其库中的所有字符组织成代码表每个字符都被赋予一个唯一的数字索引。这个数字索引称为码位。
---------------------------------------------------------------------------------------------------------------------------------
码位
在字符编码术语中码位或称编码位置即英文的code point或code position是组成码空间或代码页的数值。 例如ASCII码包含128个码位范围是016进制到7F16进制扩展ASCII码包含256个码位范围是016进制到FF16进制而Unicode包含1,114,112个码位范围是016进制到10FFFF16进制。Unicode码空间划分为17个Unicode字符平面基本多文种平面16个辅助平面每个平面有65,536 216个码位。因此Unicode码空间总计是17 × 65,536 1,114,112.
定义 码位的抽象意涵, 不同于下列概念:
1.作为具体编码的比特流。例如UTF-16编码的比特流既可以是大尾序也可以是小尾序。 2.具有特定字形的字符. 因为字符集中的字符码位的具体外观随字体font——字体显示样式——的不同而变化。 3.特定码空间的编码方式。例如一个Unicode码空间的码位可以用UTF-8编码也可以用UTF-16编码。 4.用不同字形显示一个字符即字位.
---------------------------------------------------------------------------------------------------------------------------------
在 Elixir 中您可以在字符文字前使用 ? 来显示其码位
iex?a 97 iex?ł 322
请注意大多数 Unicode 代码表将通过其十六进制 (hex) 表示来引用码位例如97转换为十六进制的0061我们可以使用 \uXXXX 符号和其码位号的十六进制表示来表示 Elixir 字符串中的任何 Unicode 字符
iex“\u0061”“a” true iex0x0061 97 ?a 97
十六进制表示还可以帮助您查找有关码位的信息例如 https://codepoints.net/U0061 有一个关于小写字母 a又名码位 97的数据表。
UTF-8 和编码
现在我们了解了什么是 Unicode 标准以及什么是码位我们终于可以讨论编码了。码位是我们存储的内容而编码则涉及我们如何存储它编码是一种实现。换句话说我们需要一种机制将码位数字转换为字节以便它们可以存储在内存中、写入磁盘等。
Elixir 使用 UTF-8 对其字符串进行编码这意味着码位被编码为一系列 8 位字节。UTF-8 是一种可变宽度字符编码使用一到四个字节来存储每个码位。它能够对所有有效的 Unicode码位进行编码。让我们看一个例子
iexstring héllo héllo iexString.length(string) 5 iexbyte_size(string) 6
虽然上面的字符串有 5 个字符但它使用了 6 个字节因为使用两个字节来表示字符 é。
注意如果您在 Windows 上运行您的终端可能默认不使用 UTF-8。您可以在输入 iex (iex.bat) 之前运行 chcp 65001 来更改当前会话的编码。
除了定义字符外UTF-8 还提供了字素的概念。字素可能由多个通常被视为一个的字符组成。例如女消防员表情符号表示为三个字符的组合女性表情符号 ()、隐藏的零宽度连接符和消防车表情符号 ()
iexString.codepoints() [, , ] iexString.graphemes() []
但是Elixir 足够聪明知道它们被视为单个字符因此长度仍然为 1
iexString.length() 1
注意如果您在终端中看不到上面的表情符号则需要确保您的终端支持表情符号并且您正在使用可以呈现它们的字体。
虽然这些规则听起来很复杂但 UTF-8 编码的文档随处可见。此页面本身以 UTF-8 编码。编码信息会提供给您的浏览器然后浏览器会知道如何相应地呈现所有字节、字符和字素。
如果您想查看字符串在文件中存储的确切字节数一个常用技巧是将空字节 0 连接到它
iex“hełło” 0 104, 101, 197, 130, 197, 130, 111, 0
或者您可以使用 IO.inspect/2 查看字符串的二进制表示
iexIO.inspect(“hełło”, binaries: :as_binaries) 104, 101, 197, 130, 197, 130, 111
我们有点超前了。让我们讨论一下位串了解 构造函数的确切含义。
二进制字符串
虽然我们已经介绍了码位和 UTF-8 编码但我们仍需要更深入地了解我们究竟如何存储编码字节这就是我们介绍二进制字符串的地方。二进制字符串是 Elixir 中的基本数据类型用 /1 语法表示。二进制字符串是内存中连续的位序列。
默认情况下使用 8 位即 1 个字节将每个数字存储在二进制字符串中但您可以通过 ::n 修饰符手动指定位数以 n 位表示大小或者可以使用更详细的声明 ::size(n)
iex42 42::8 true iex3::4 3::size(4)
例如十进制数 3 用 4 位二进制表示时为 0011相当于值 0、0、1、1每个值使用 1 位存储
iex0::1, 0::1, 1::1, 1::1 3::4 true
任何超出预置位数可存储的值都将被截断
iex1 257 true
此处257 二进制表示为100000001但由于我们只保留了 8 位来表示它默认情况下最左边的位将被忽略并且该值将被截断为 00000001或者仅仅是十进制的 1。
二进制序列
二进制序列是位数可被 8 整除的二进制字符串。这意味着每个二进制二进制序列都是二进制字符串但并非每个二进制字符串都是二进制二进制序列。我们可以使用 is_bitstring/1 和 is_binary/1 函数来演示这一点。
iexis_bitstring(3::4) true iexis_binary(3::4) false iexis_bitstring(0, 255, 42) true iexis_binary(0, 255, 42) true iexis_binary(42::16) true
我们可以对二进制二进制序列/二进制字符串进行模式匹配
iex0, 1, x 0, 1, 2 0, 1, 2 iexx 2 iex0, 1, x 0, 1, 2, 3 ** (MatchError) no match of right hand side value: 0, 1, 2, 3
请注意除非您明确使用 :: 修饰符否则二进制序列模式中的每个条目都应匹配单个字节正好 8 位。如果我们想要匹配未知大小的二进制序列我们可以在模式末尾使用 binary 修饰符
iex0, 1, x::binary 0, 1, 2, 3 0, 1, 2, 3 iexx 2, 3
在二进制序列上进行模式匹配时还有其他几个修饰符很有用。binary-size(n) 修饰符将匹配二进制序列中的 n 个字节
iexhead::binary-size(2), rest::binary 0, 1, 2, 3 0, 1, 2, 3 iexhead 0, 1 iexrest 2, 3
字符串是 UTF-8 编码的二进制其中每个字符的码位使用 1 到 4 个字节进行编码。因此每个字符串都是二进制序列但由于 UTF-8 标准编码规则并非每个二进制序列都是有效字符串。
iexis_binary(hello) true iexis_binary(239, 191, 19) true iexString.valid?(239, 191, 19) false
字符串连接运算符 实际上是二进制序列连接运算符
iexa ha aha iex0, 1 2, 3 0, 1, 2, 3
鉴于字符串是二进制序列的我们也可以对字符串进行模式匹配
iexhead, rest::binary banana banana iexhead ?b true iexrest anana
但是请记住二进制序列模式匹配适用于bytes因此对多字节字符的字符串如“über”进行匹配不会匹配该字符它将匹配该字符的第一个字节
iexü 0 195, 188, 0 iexx, rest::binary über über iexx ?ü false iexrest 188, 98, 101, 114
上面x 仅匹配多字节 ü 字符的第一个字节。
因此在对字符串进行模式匹配时使用 utf8 修饰符非常重要
iexx::utf8, rest::binary über über iexx ?ü true iexrest ber
字符列表(Charlists)
我们对二进制字符串、二进制和字符串的介绍已接近尾声但我们还需要解释一种数据类型Charlists。
字符列表是整数列表其中所有整数都是有效码位。实际上您不会经常遇到它们只有在特定场景中才会遇到例如与不接受二进制作为参数的旧 Erlang 库交互。
iex~chello ~chello iex[?h, ?e, ?l, ?l, ?o] ~chello
~c 符号我们将在“符号”一章后面介绍符号表示我们正在处理字符列表而不是常规字符串。
字符列表包含整数码位而不是字节。但是只有当所有码位都在 ASCII 范围内时列表才会以符号形式打印
iex~chełło [104, 101, 322, 322, 111] iexis_list(~chełło) true
这样做是为了简化与 Erlang 的互操作性尽管这可能会导致一些令人惊讶的行为。例如如果您存储的整数列表恰好在 0 到 127 之间则默认情况下 IEx 会将其解释为字符列表并显示相应的 ASCII 字符。
iexheartbeats_per_minute [99, 97, 116] ~ccat
您始终可以通过调用 inspect/2 函数强制将字符列表打印在其列表表示中
iexinspect(heartbeats_per_minute, charlists: :as_list) [99, 97, 116]
此外您可以使用 to_string/1 和 to_charlist/1 将字符列表转换为字符串并转换回
iexto_charlist(hełło) [104, 101, 322, 322, 111] iexto_string(~chełło) hełło iexto_string(:hello) hello iexto_string(1) 1
上述函数是多态的换句话说它们接受多种形状它们不仅可以将字符列表转换为字符串反之亦然还可以转换整数、原子等等。
字符串二进制连接使用 运算符但字符列表作为列表使用列表连接运算符
iex~cthis ~cfails ** (ArgumentError) expected binary argument in operator but got: ~cthis (elixir) lib/kernel.ex:1821: Kernel.wrap_concatenation/3 (elixir) lib/kernel.ex:1808: Kernel.extract_concatenations/2 (elixir) expanding macro: Kernel./2 iex:1: (file) iex~cthis ~cworks ~cthis works iexhe llo ** (ArgumentError) argument error :erlang.(he, llo) iexhe llo hello
讨论完二进制、字符串和字符列表后是时候讨论键值数据结构了。