【问题标题】:byte_size vs String.length in elixir长生不老药中的字节大小与字符串长度
【发布时间】:2019-08-04 13:49:07
【问题描述】:

我决定在 elixir 中构建我自己的 CSV 解析器作为一个实践项目,并设法让一些工作顺利进行。

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

我开始查看 elixir 模块 NimbleCSV 的源代码。它由该语言的创造者 José Valim 编写,并得到了一些著名的 elixir 开发者的贡献,所以我认为这是一个不错的选择。

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?如果他们只是得到一个字符串的长度不会都返回相同的结果?

【问题讨论】:

    标签: string binary elixir


    【解决方案1】:

    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

    【讨论】:

    • 另一个原因是我们不能在字素上进行模式匹配,并且整个实现是基于二进制匹配的,这提高了 e 的性能。 G。 looking up newlines。基本上,我们需要获取行分隔符和单元格分隔符,并且由于 NimbleCSV 不允许 UTF-8 分隔符,因此通常可以忘记 Unicode,并将分隔符之间的所有内容都视为二进制垃圾。
    • 也就是说,如果想要一个 ESV(对于 Emoji Serarated Values :),实现必须使用 Strings。
    猜你喜欢
    • 1970-01-01
    • 2017-01-03
    • 2016-02-01
    • 1970-01-01
    • 2010-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多