药剂中的byte_size vs String.length

时间:2019-03-13 19:00:50

标签: string binary elixir

我决定在elixir中构建自己的CSV解析器作为练习项目,并设法使工作正常进行而没有太多麻烦。

我知道这是一些“顶级”长生不老药开发者过去解决的问题,所以我决定看看他们是如何解决的。

我开始查看elixir模块NimbleCSV的源代码。它是由该语言的创建者何塞·瓦利姆(JoséValim)编写的,并得到了一些著名的长生不老药开发者的贡献,因此我认为这是一个不错的选择。

parse_string函数中,他们使用函数byte_size(string)检查字符串的长度。我想我了解此功能的工作原理。例如

iex()> byte_size(<<104, 101, 108, 108, 111>>)
5
iex()> byte_size(<<104, 101, 108, 108, 111::9>>)
6

第一个函数是40 bits,它是5 bytes(如果没有另外说明,二进制文件中的每个值默认为elixir中的8位)

在第二个步骤中,我将其中一个值分配为9 bits,因此总数为41 bits。这意味着它是6 bytes(由于四舍五入)

  

抱歉,某些语言不正确

这对我来说很有意义。我的问题是,在这种情况下,为什么他们会选择此功能而不是String.length?如果它们只是获取字符串的长度,那么两者都不会返回相同的结果吗?

1 个答案:

答案 0 :(得分:3)

String.length/1返回graphemes的数字(每个数字可以是一个或多个字节),而byte_size/1处理原始数据字节。

iex> byte_size "‍‍"
18
iex>  "‍‍" <> <<0>>
<<240, 159, 145, 169, 226, 128, 141, 240, 159, 145, 169, 226, 128, 141, 240, 159, 145, 167, 0>>

iex> String.length "‍‍"
1

iex> String.length "a"
1
iex> byte_size "a"
1

来自doc

  

字符串和二进制操作

     

要按照Unicode标准执行操作,此模块中的许多函数都以​​线性时间运行,因为它们需要考虑正确的Unicode代码点遍历整个字符串。

     

例如,String.length/1将随着输入的增加而花费更长的时间。另一方面,Kernel.byte_size/1始终以恒定时间运行(即与输入大小无关)。

没有直接关系,但是如果您想进一步了解Unicode和char编码,可以阅读this article并观看this video