replace.ha (2442B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use bytes; 5 6 // Returns a new string duplicated from 's', but with all instances of 'needle' 7 // replaced with 'target'. The caller must free the return value. 8 export fn replace(s: str, needle: str, target: str) str = { 9 return multireplace(s, (needle, target)); 10 }; 11 12 // Performs a replacement in 's' of each tuple given by 'repls'. Replacement 13 // occurs in a single pass of 's', and works like in [[replace]], except that 14 // replacement pairs found earlier in 'repls' will take precedence over later 15 // ones. For example: 16 // 17 // assert(multireplace("hello there", ("e", "a"), ("a", "x"), ("ell", "eww")) == "hallo thara"); 18 // assert(multireplace("hello there", ("ell", "eww"), ("e", "a")) == "hewwo thara"); 19 // 20 // The caller must free the return value. 21 export fn multireplace(s: str, repls: (str, str)...) str = { 22 let b = toutf8(s); 23 let res: []u8 = []; 24 let i = 0z; 25 let prev = 0z; // end of previous match, so we can append in chunks 26 for :step (i < len(b)) { 27 for (let (replace, with) .. repls) { 28 const replb = (toutf8(replace), toutf8(with)); 29 if (bytes::hasprefix(b[i..], replb.0)) { 30 append(res, b[prev..i]...); 31 append(res, replb.1...); 32 i += len(replb.0); 33 prev = i; 34 continue :step; 35 }; 36 }; 37 i += 1; 38 }; 39 append(res, b[prev..i]...); 40 return fromutf8_unsafe(res); 41 }; 42 43 @test fn replace() void = { 44 const s = replace("Hello world!", "world", "there"); 45 defer free(s); 46 assert(s == "Hello there!"); 47 48 const s = replace("I like dogs, dogs, birds, dogs", "dogs", "cats"); 49 defer free(s); 50 assert(s == "I like cats, cats, birds, cats"); 51 52 const s = replace("aaaaaa", "aa", "a"); 53 defer free(s); 54 assert(s == "aaa"); 55 56 const s = replace("aaa", "a", "aa"); 57 defer free(s); 58 assert(s == "aaaaaa"); 59 60 const s = replace("こんにちは", "にち", "ばん"); 61 defer free(s); 62 assert(s == "こんばんは"); 63 }; 64 65 @test fn multireplace() void = { 66 const s = multireplace("Hello world", 67 ("Hello", "Greetings"), ("world", "globe")); 68 defer free(s); 69 assert(s == "Greetings globe"); 70 71 const s = multireplace("ababa", ("a", "ba"), ("b", "a"), ("a", "c")); 72 defer free(s); 73 assert(s == "baabaaba"); 74 75 const s = multireplace("hello there", ("e", "a"), 76 ("a", "x"), ("ell", "eww")); 77 defer free(s); 78 assert(s == "hallo thara"); 79 80 const s = multireplace("hello there", ("ell", "eww"), ("e", "a")); 81 defer free(s); 82 assert(s == "hewwo thara"); 83 };