【问题标题】:Count codepoints in a string in Elixir在 Elixir 中计算字符串中的代码点
【发布时间】:2021-06-20 11:22:36
【问题描述】:

String.length/1 函数返回 UTF-8 二进制文件中 graphemes 的数量。

如果我想知道字符串中有多少个 Unicode codepoints,我知道我可以做到:

string |> String.codepoints |> length

但这会产生一个不必要的所有代码点的中间列表,并重复字符两次。有没有一种方法可以直接计算代码点,而无需生成中间列表?

【问题讨论】:

    标签: unicode elixir string-length codepoint


    【解决方案1】:

    您可以将comprehension 与位串生成器和reduce 选项一起使用来计算代码点,而无需建立中间列表。

    for <<_::utf8 <- string>>, reduce: 0, do: (count -> count + 1)
    

    例子:

    iex> string = "??‍♂️"
    iex> for <<_::utf8 <- string>>, reduce: 0, do: (count -> count + 1)
    5
    iex> string |> String.codepoints |> length
    5
    iex> String.length(string)
    1
    

    如果您将 utf8 替换为 utf16utf32,它还有一个额外的好处,即它也适用于 UTF-16 和 UTF-32 字符串:

    iex> utf8_string = "I'm going to be UTF-16!"
    "I'm going to be UTF-16!"
    iex> utf16_string = :unicode.characters_to_binary(utf8_string, :utf8, :utf16)
    <<0, 73, 0, 39, 0, 109, 0, 32, 0, 103, 0, 111, 0, 105, 0, 110, 0, 103, 0, 32, 0,
      116, 0, 111, 0, 32, 0, 98, 0, 101, 0, 32, 0, 85, 0, 84, 0, 70, 0, 45, 0, 49,
      0, 54, 0, 33>>
    iex> for <<_::utf8 <- utf8_string>>, reduce: 0, do: (count -> count + 1)
    23
    iex> for <<_::utf16 <- utf16_string>>, reduce: 0, do: (count -> count + 1)
    23
    

    【讨论】:

    • 我在两者之间进行了基准测试,使用您的理解比调用 Kernel.length/1 快 85%
    • @vinibrsl 好主意。但我无法重现你的结果。你是如何进行基准测试的?我只跑了一个,在我的结果中to_charlist 实际上比理解更快并且使用的内存更少,但它并没有太多。也许我需要更新这个答案...gist.github.com/adamu/911b3754736f1c584e45222ba9a4c107
    • 啊,更长的字符串? 在我的脚本中生成该字符串的结果:charlist 107.57 μs, comprehension 256.59 μs - 2.39x slower, codepoints 725.87 μs - 6.75x slower。因此,codepointsto_charlist 的理解速度似乎更快(并且使用更少的内存)。不知道为什么?有时间我会再看一遍。
    • @vinibrsl 实际上即使是你的脚本,我也得到了Codepoints took 0.6852230000000012 seconds Comprehension took 0.24642800000000145 seconds。所以你的设置有问题,也许?
    猜你喜欢
    • 2020-07-07
    • 1970-01-01
    • 2012-08-10
    • 2020-06-09
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 2021-03-06
    相关资源
    最近更新 更多