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