Elixir 中的 byte_size 与 String.length

Rob*_*ion 2 string binary elixir

我决定在 Elixir 中构建自己的 CSV 解析器作为练习项目,并成功地让一些东西顺利运行。

\n\n

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

\n\n

我开始查看 elixir 模块NimbleCSV的源代码。它是由该语言的创建者 Jos\xc3\xa9 Valim 编写的,还有一些著名的 Elixir 开发人员的贡献,所以我认为这是一个不错的选择。

\n\n

parse_string函数中,他们使用函数检查字符串长度byte_size(string)。我想我明白这个功能是如何工作的。例如

\n\n
iex()> byte_size(<<104, 101, 108, 108, 111>>)\n5\niex()> byte_size(<<104, 101, 108, 108, 111::9>>)\n6\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

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

\n\n
\n

抱歉,如果某些语言不完全正确

\n
\n\n

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

\n

fhd*_*sni 6

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

\n
iex> byte_size "\xe2\x80\x8d\xe2\x80\x8d"\n18\niex>  "\xe2\x80\x8d\xe2\x80\x8d" <> <<0>>\n<<240, 159, 145, 169, 226, 128, 141, 240, 159, 145, 169, 226, 128, 141, 240, 159, 145, 167, 0>>\n\niex> String.length "\xe2\x80\x8d\xe2\x80\x8d"\n1\n\niex> String.length "a"\n1\niex> byte_size "a"\n1\n
Run Code Online (Sandbox Code Playgroud)\n

来自文档

\n
\n

字符串和二元运算

\n

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

\n

例如,String.length/1随着输入的增加,将需要更长的时间。另一方面,Kernel.byte_size/1总是以恒定的时间运行(即无论输入大小如何)。

\n
\n

不直接相关,但如果您想了解有关 Unicode 和 char 编码的更多信息,您可以阅读这篇文章并观看此视频

\n

  • 也就是说,如果想要一个 ESV(用于表情符号分级值:),则实现必须使用“String”。 (3认同)
  • 另一个原因是我们无法对字素进行模式匹配,并且整个实现基于二进制匹配,这提高了性能,例如[查找换行符](https://github.com/plataformatec/nimble_csv/blob/master/lib/ nimble_csv.ex#L385)。基本上,我们需要获取行分隔符和单元格分隔符,并且由于“NimbleCSV”不允许 UTF-8 分隔符,因此通常可能会忘记 Unicode 并将分隔符之间的所有内容视为二进制垃圾。 (2认同)