如何用字符串中的新值替换旧值列表

时间:2016-08-09 12:58:17

标签: elixir

拥有old_new值的映射,用字符串中的new_values替换那些old_value的惯用方法是什么?

my_map = %{"old_value1": "new_value1", "old_value2": "new_value2"}
str = "some string .......old_value1 fafdsfd old_value2 faaaaaaa"

由于Elixir是不可改变的,我不知道该怎么做。

1 个答案:

答案 0 :(得分:2)

(我假设你的地图有字符串键,而不是Atoms。)

如果您一个接一个地运行替换,那么您可以将Enum.reduceString.replace一起使用:

iex(1)> my_map = %{"old_value1" => "new_value1", "old_value2" => "new_value2"}
%{"old_value1" => "new_value1", "old_value2" => "new_value2"}
iex(2)> str = "some string .......old_value1 fafdsfd old_value2 faaaaaaa"
"some string .......old_value1 fafdsfd old_value2 faaaaaaa"
iex(3)> Enum.reduce(my_map, str, fn {old, new}, str -> String.replace(str, old, new) end)
"some string .......new_value1 fafdsfd new_value2 faaaaaaa"

但是如果你想并行运行它们,为了性能或正确性(如果地图的任何一个键与任何其他值匹配,之前的解决方案会给出不同的结果),我会使用{{1 },:binary.compile_pattern和模式匹配:

:binary.match

输出:

defmodule Main do
  def replace(string, map) do
    replace(string, map, :binary.compile_pattern(Map.keys(map)), "")
  end

  defp replace(string, map, pattern, acc) do
    case :binary.match(string, pattern) do
      {start, length} ->
        <<before::binary-size(start), match::binary-size(length), rest::binary>> = string
        replacement = map[match]
        replace(rest, map, pattern, acc <> before <> replacement)
      :nomatch ->
        acc <> string
    end
  end
end

my_map = %{"old_value1" => "new_value1", "old_value2" => "new_value2"}
str = "some string .......old_value1 fafdsfd old_value2 faaaaaaa"
IO.puts Main.replace(str, my_map)