summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2016-09-22 06:14:27 -0700
committerKaz Kylheku <kaz@kylheku.com>2016-09-22 06:14:27 -0700
commit75c8ed7c7ea232e98b1e6d0ba85ce269f5ea3fe7 (patch)
tree67898edda2983dda7283a4a4d42e037dc0b9f384
parent031384f551286723a1e82b8b729905f22bc15822 (diff)
downloadtxr-75c8ed7c7ea232e98b1e6d0ba85ce269f5ea3fe7.tar.gz
txr-75c8ed7c7ea232e98b1e6d0ba85ce269f5ea3fe7.tar.bz2
txr-75c8ed7c7ea232e98b1e6d0ba85ce269f5ea3fe7.zip
Support functional argument in regsub.
* regex.c (regsub): Allow the second argument to be a function, which is called with str as an argument, and returns a range which indicates what part of the string is to be replaced, or else nil. * txr.1: Documented functional argument of regsub.
-rw-r--r--regex.c64
-rw-r--r--txr.122
2 files changed, 59 insertions, 27 deletions
diff --git a/regex.c b/regex.c
index c7a5e132..ba63132c 100644
--- a/regex.c
+++ b/regex.c
@@ -2523,34 +2523,52 @@ val match_regex_right(val str, val regex, val end)
val regsub(val regex, val repl, val str)
{
- list_collect_decl (out, ptail);
- val pos = zero;
val isfunc = functionp(repl);
- do {
- cons_bind (find, len, search_regex(str, regex, pos, nil));
- if (!find) {
- if (pos == zero)
- return str;
- ptail = list_collect(ptail, sub_str(str, pos, nil));
- break;
+ if (functionp(regex)) {
+ val range = funcall1(regex, str);
+
+ if (!range)
+ return str;
+
+ {
+ val rf = from(range);
+ val rt = to(range);
+
+ return replace_str(str, if3(isfunc,
+ funcall1(repl, sub_str(str, rf, rt)),
+ repl),
+ rf, rt);
}
- ptail = list_collect(ptail, sub_str(str, pos, find));
- ptail = list_collect(ptail, if3(isfunc,
- funcall1(repl, sub_str(str, find,
- plus(find, len))),
- repl));
- if (len == zero && eql(find, pos)) {
- if (lt(pos, length_str(str))) {
- ptail = list_collect(ptail, chr_str(str, pos));
- pos = plus(pos, one);
+ } else {
+ list_collect_decl (out, ptail);
+ val pos = zero;
+
+ do {
+ cons_bind (find, len, search_regex(str, regex, pos, nil));
+ if (!find) {
+ if (pos == zero)
+ return str;
+ ptail = list_collect(ptail, sub_str(str, pos, nil));
+ break;
}
- } else {
- pos = plus(find, len);
- }
- } while (lt(pos, length_str(str)));
+ ptail = list_collect(ptail, sub_str(str, pos, find));
+ ptail = list_collect(ptail, if3(isfunc,
+ funcall1(repl, sub_str(str, find,
+ plus(find, len))),
+ repl));
+ if (len == zero && eql(find, pos)) {
+ if (lt(pos, length_str(str))) {
+ ptail = list_collect(ptail, chr_str(str, pos));
+ pos = plus(pos, one);
+ }
+ } else {
+ pos = plus(find, len);
+ }
+ } while (lt(pos, length_str(str)));
- return cat_str(out, nil);
+ return cat_str(out, nil);
+ }
}
val search_regst(val haystack, val needle_regex, val start_num, val from_end)
diff --git a/txr.1 b/txr.1
index 205f25cc..0256d039 100644
--- a/txr.1
+++ b/txr.1
@@ -31860,15 +31860,18 @@ matching substring of
.coNP Function @ regsub
.synb
-.mets (regsub < regex < replacement << string )
+.mets (regsub >> { regex | << function } < replacement << string )
.syne
.desc
The
.code regsub
-function searches
+function operates in two modes, depending on whether
+the second argument is a regular expression,
+or function.
+
+If the second argument is a regular expression it searches
.meta string
-for multiple occurrences of
-non-overlapping matches for
+for multiple occurrences of non-overlapping matches for that
.metn regex .
A new string is constructed
similar to
@@ -31891,6 +31894,17 @@ which case for every match which is found, this function is invoked,
with the matching piece of text as an argument. The function's
return value is then taken to be the replacement text.
+If the second argument is a function, then it is called, with
+.meta string
+as its argument. The return value must be either a range
+object (see the
+.code rcons
+function) which indicates the extent of
+.meta string
+to be replaced, or else
+.code nil
+which indicates that no replacement is to take place.
+
.TP* Examples:
.cblk