@@ -190,6 +190,101 @@ pub fn (s string) replace(rep, with string) string {
190190 return tos (b, new_len)
191191}
192192
193+ struct RepIndex {
194+ idx int
195+ val_idx int
196+ }
197+
198+ fn (a mut []RepIndex) sort () {
199+ a.sort_with_compare (compare_rep_index)
200+ }
201+
202+
203+ // TODO
204+ /*
205+ fn (a RepIndex) < (b RepIndex) bool {
206+ return a.idx < b.idx
207+ }
208+ */
209+
210+ fn compare_rep_index (a, b & RepIndex) int {
211+ if a.idx < b.idx {
212+ return - 1
213+ }
214+ if a.idx > b.idx {
215+ return 1
216+ }
217+ return 0
218+ }
219+
220+ pub fn (s string) replace_each (vals []string ) string {
221+ if s.len == 0 || vals.len == 0 {
222+ return s
223+ }
224+ if vals.len % 2 != 0 {
225+ println ('string.replace_many(): odd number of strings' )
226+ return s
227+ }
228+ // `rep` - string to replace
229+ // `with` - string to replace with
230+ // Remember positions of all rep strings, and calculate the length
231+ // of the new string to do just one allocation.
232+ mut new_len := s.len
233+ mut idxs := []RepIndex
234+ mut idx := 0
235+ for rep_i := 0 ; rep_i < vals.len; rep_i+ = 2 {
236+ // vals: ['rep1, 'with1', 'rep2', 'with2']
237+ rep := vals[rep_i]
238+ with := vals[rep_i+ 1 ]
239+ for {
240+ idx = s.index_after (rep, idx)
241+ if idx == - 1 {
242+ break
243+ }
244+ // We need to remember both the position in the string,
245+ // and which rep/with pair it refers to.
246+ idxs << RepIndex{idx, rep_i}
247+ idx++
248+ new_len + = with.len - rep.len
249+ }
250+ }
251+ // Dont change the string if there's nothing to replace
252+ if idxs.len == 0 {
253+ return s
254+ }
255+ idxs.sort ()
256+ mut b := malloc (new_len + 1 )// add a \0 just in case
257+ // Fill the new string
258+ mut idx_pos := 0
259+ mut cur_idx := idxs[idx_pos]
260+ mut b_i := 0
261+ for i := 0 ; i < s.len; i++ {
262+ // Reached the location of rep, replace it with "with"
263+ if i == cur_idx.idx {
264+ rep := vals[cur_idx.val_idx]
265+ with := vals[cur_idx.val_idx+ 1 ]
266+ for j := 0 ; j < with.len; j++ {
267+ b[b_i] = with[j]
268+ b_i++
269+ }
270+ // Skip the length of rep, since we just replaced it with "with"
271+ i + = rep.len - 1
272+ // Go to the next index
273+ idx_pos++
274+ if idx_pos < idxs.len {
275+ cur_idx = idxs[idx_pos]
276+ }
277+ }
278+ // Rep doesnt start here, just copy
279+ else {
280+ b[b_i] = s[i]
281+ b_i++
282+ }
283+ }
284+ b[new_len] = `\0`
285+ return tos (b, new_len)
286+ }
287+
193288pub fn (s string) bool () bool {
194289 return s == 'true' || s == 't' // TODO t for pg, remove
195290}
0 commit comments