String.replace返回字符串的二进制表示形式



我正在学习长生不老药,遇到了一些对我来说没有意义的东西…

我正在尝试删除标点符号

"Freude schöner Götterfunken" |> String.replace(~r/[^sw]/, "") #=> <<70, 114, 101, 117, 100, 101, 32, 115, 99, 104, 195, 110, 101, 114, 32, 71, 195, 116, 116, 101, 114, 102, 117, 110, 107, 101, 110>>
"Freude schöner Götterfunken" |> String.replace(~r/[^w]/, "") #=> <<70, 114, 101, 117, 100, 101, 32, 115, 99, 104, 195, 110, 101, 114, 32, 71, 195, 116, 116, 101, 114, 102, 117, 110, 107, 101, 110>>
"Freude schöner Götterfunken" |> String.replace(~r/p{P}/, "") #=> <<70, 114, 101, 117, 100, 101, 32, 115, 99, 104, 195, 110, 101, 114, 32, 71, 195, 116, 116, 101, 114, 102, 117, 110, 107, 101, 110>>
"Freude schöner Götterfunken" |> String.replace(~r/s/, "") #=> FreudeschönerGötterfunken
"Hi my name is bob" |> String.replace(~r/w/, "") #=> "    "
Regex.run(~r/[^w]/, "Freude schöner Götterfunken") #=> [<<182>>]

这看起来像是一个bug,但作为一个角落,我认为这是无知。为什么replace不返回字符串?

String.replace/2没有返回字符串,因为Elixir将字符串定义为utf-8编码的二进制文件。然而,这并不是一个错误,因为Elixir希望您对参数传递或执行有效的操作,因为它不会验证所有结果(因为成本高昂)。

例如,如果您将上面的任何二进制文件传递给String.downcase/1,Elixir将向下转换它所知道的部分,而忽略其余部分。它之所以有效,是因为UTF-8会自动同步,所以如果我们看到奇怪的东西,我们可以跳过奇怪的字节,继续执行操作。

换句话说,Elixir中字符串处理的原理是在边界处进行验证(例如打开文件、执行I/O或从数据库读取时),并假设我们始终在处理和执行有效操作。

好吧,既然如此,为什么你的代码不起作用?原因是您的regex没有启用unicode。让我们添加u修饰符,然后:

iex> "Freude schöner Götterfunken" |> String.replace(~r/[^sw]/u, "")
"Freude schöner Götterfunken"

好吧,它不能解决你的问题,但至少结果是有效的。在这里阅读有关unicode类别的信息意味着我们无法用unicode属性真正解决这个问题,因为您的示例中的ö是与p{L}属性匹配的单个代码点。

在这种情况下,假设您只想为德语解决它,也许最简单的解决方案是遍历二进制文件,保持字节<=127.类似

iex> for <<x <- "Freude schöner Götterfunken">>, x <= 127, into: "", do: <<x>>
"Freude schner Gtterfunken"

如果您想要一个更完整的解决方案,您可能应该研究unicode音译。

String.replace返回一个"字符串",但双引号字符串实际上是作为二进制文件存储在Elixir中的。由于某些原因,输出不能显示为常规字符串,因此,它又回到显示二进制表示。

相关内容

最新更新