0%

erlang使用RE进行字符串替换的坑

erlang使用RE进行字符串替换时”&”特殊处理

找问题

先来贴一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
replace(String, []) ->
String;
replace(String, [{RE,Replacement}|Left]) ->
NewString = replace(String, RE, Replacement),
replace(NewString, Left).

replace(String, RE, Replacement) ->
case re:run(String, RE) of
nomatch -> String;
_ ->
NewString = re:replace(String, RE, NewReplacement, [{return,list}]),
replace(NewString, RE, Replacement)
end.

这块代码有两个问题:

  1. [小问题]在11,12行可以使用re:replace(String, RE, NewReplacement, [{return,list}, global])代替
  2. [大问题]这块代码会造成死循环, 重现方式:replace("abcdefg", [{"a", "&"}]).

解决方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
%% 替换字符串内容
%% A = re:replace("a&b", "&", "\\\\\\&", [{return,list}]).
%% util:replace("{0}aaa{1}", [{"\\{0\\}", A}]).
%% util:replace("{0}aaa{1}", [{"\\{0\\}", "a&b"}]).
replace(String, []) ->
String;
replace(String, [{RE,Replacement}|Left]) ->
NewString = replace(String, RE, Replacement),
replace(NewString, Left).

replace(String, RE, Replacement) ->
case re:run(String, RE) of
nomatch -> String;
_ ->
NewReplacement = re:replace(Replacement, "&", "\\\\\\&", [global, {return,list}]),
NewString = re:replace(String, RE, NewReplacement, [{return,list}, global]),
NewString
end.