我决定在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
?如果它们只是获取字符串的长度,那么两者都不会返回相同的结果吗?
答案 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