hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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 };