ref: 97d9da73218273da5b0f7657c86df50b8fc0d127
parent: ce1c3bf2557c737b087401365884e678e9b9b8d4
author: henesy <unknown>
date: Thu Dec 10 09:23:38 EST 2020
string(2): add replace() for string replacement
--- a/appl/lib/string.b
+++ b/appl/lib/string.b
@@ -425,3 +425,73 @@
return unquoted(s + "'");
return args;
}
+
+# Replace up to 'max' instances of 's' with 'with' in 'in'
+replace(in, s, with: string, max: int): string {
+ if(max == 0 || s == "") {
+ # Nothing to replace
+ return in;
+ }
+ if(len in < 1) {
+ # No string given
+ return "";
+ }
+
+ n := 0;
+
+ # For each rune 'in' the original string
+ for(r0 := 0; r0 < len in ; r0++) {
+ # Try to build 's'
+ r1: int;
+
+ substring:
+ for(r1 = 0; r1 < len s; r1++) {
+ if(in[r0 + r1] == s[r1]) {
+ # Match so far
+ continue substring;
+ } else {
+ # No longer matches
+ break substring;
+ }
+ }
+
+ # We didn't break the loop, this is a match
+ # String will be [r0 , r0+len(s))
+ if(r1 >= len s) {
+ left, right: string;
+
+ # Left side
+ case r0 {
+ 0 =>
+ # First rune, no left side
+ left = "";
+ * =>
+ left = in[:r0];
+ }
+
+ # Right side
+ redge := r0 + len s;
+
+ if(redge == len in - 1)
+ # Last rune
+ right = "";
+ else
+ right = in[redge:];
+
+ # Insert
+ in = left + with + right;
+
+ # Skip forward to end of replacement string
+ r0 = r0 + (len with - 1);
+
+ # Tick counts
+ n++;
+ if(n == max && max > 0) {
+ # We hit max and care about the number of replacements
+ return in;
+ }
+ }
+ }
+
+ return in;
+}
--- a/man/2/string
+++ b/man/2/string
@@ -13,6 +13,7 @@
prefix: fn(pre, s: string): int;
splitl: fn(s, cl: string): (string, string);
splitr: fn(s, cl: string): (string, string);
+replace: fn(in, s, with: string, max: int): string;
splitstrl: fn(s, t: string): (string, string);
splitstrr: fn(s, t: string): (string, string);
take: fn(s, cl: string): string;
@@ -110,6 +111,30 @@
.IR s ,
the result is
.RI ( nil, s ).
+
+.PP
+.B Replace
+returns the string
+.I in
+with up to
+.I max
+instances of
+.I s
+removed and replaced by
+.IR with .
+If
+.I max
+is less than 0, there is no limit to the number of replacements.
+If
+.I max
+is 0 or
+.I s
+is
+.IR nil ,
+the string
+.I in
+is returned unchanged.
+
.PP
.B Take
returns the maximal prefix of string
--- a/module/string.m
+++ b/module/string.m
@@ -20,6 +20,7 @@
# in these, the second string is a string to match, not a class
splitstrl: fn(s, t: string): (string, string);
splitstrr: fn(s, t: string): (string, string);
+ replace: fn(in, s, with: string, max: int): string;
# is first arg a prefix of second?
prefix: fn(pre, s: string): int;