由于您只想在第一次出现时拆分,我建议在这里使用:binary.match/3 和:binary.part/3。 :binary.match/3 返回匹配索引的元组和匹配成功的长度,然后可以与:binary.part/2 一起使用来拆分二进制文件。
defmodule A do
def split(binary) do
case :binary.match(binary, ["{", "}"]) do
{start, length} ->
before = :binary.part(binary, 0, start)
match = :binary.part(binary, start, length)
after_ = :binary.part(binary, start + length, byte_size(binary) - (start + length))
{before, match, after_}
:nomatch -> nil
end
end
end
IO.inspect A.split("foo { bar") |> IO.inspect
IO.inspect A.split("foo } bar") |> IO.inspect
IO.inspect A.split("foo + bar") |> IO.inspect
输出:
{"foo ", "{", " bar"}
{"foo ", "{", " bar"}
{"foo ", "}", " bar"}
{"foo ", "}", " bar"}
nil
nil
此实现仅在 :binary.match/3 调用中遍历字符串一次。使用的所有其他函数和操作都是O(1)。
我在我正在研究的 XML 解析器中使用了类似的方法,与二进制文件上的递归模式匹配相比,它提供了巨大的速度。
编辑:您可以使用模式匹配来使这段代码更短,而且我很确定与上面完全相同的性能:
defmodule A do
def split(binary) do
case :binary.match(binary, ["{", "}"]) do
{start, length} ->
<<a::binary-size(start), b::binary-size(length), c::binary>> = binary
{a, b, c}
:nomatch -> nil
end
end
end