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