1 module util.replace;
2 import std.conv;
3 
4 /**
5 Performs compile time string replacements on $(D base)
6 
7 Parameters:
8 
9 T = replacement specs, alternating between string to be replaced and $(D toStringNow)-able object to replace with.
10 
11 Example:
12 ---
13 import std.stdio;
14 
15 void main()
16 {
17   string s = Replace!(q{$ret func(T)(T t){ return new $ret(t+$i); }},
18     "$ret", "C",
19     "$i", 5000);
20   writeln(s); // "C func(T)(T t){ return new C(t+5000); }"
21 }
22 ---
23 If there is ambiguity between two substrings to replace, the longer one is preferred:
24 ---
25 enum s = Replace!("boy eats boysenberry", "boy", "girl", "boysenberry", "plum");
26 writeln(s) // "girl eats plum"
27 ---
28  */
29 template Replace(string base, T...)
30 {
31     import std.algorithm;
32     static assert(T.length % 2 == 0);
33     template NextAt(string base, string longest_spec,
34             size_t _at0, size_t _ti0, T...)
35     {
36         static assert(T.length % 2 == 0);
37         static if(T.length == 0)
38         {
39             static if(_at0 == -1)
40             {
41                 enum size_t at = base.length;
42                 enum size_t ti = -1;
43             }
44             else
45             {
46                 enum at = _at0;
47                 enum ti = _ti0;
48             }
49         }
50         else
51         {
52             enum size_t _at1 = countUntil(base, T[$-2]);
53             static if(_at1 < _at0 ||
54                     _at1 == _at0 && T[$-2].length > longest_spec.length)
55             {
56                 alias NextAt!(base, T[$-2], _at1, T.length-2,T[0 .. $-2]) N2;
57             }
58             else
59             {
60                 alias NextAt!(base,longest_spec,_at0,_ti0,T[0 .. $-2]) N2;
61             }
62             enum at = N2.at;
63             enum ti = N2.ti;
64         }
65     }
66 
67 
68     alias NextAt!(base,"",-1,-1,T) N;
69     static if(N.ti == -1)
70         enum Replace = base;
71     else
72         enum Replace = base[0 .. N.at] ~ to!string(T[N.ti+1]) ~
73             Replace!(base[N.at + T[N.ti].length .. $], T);
74 }
75