summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2020-10-05 06:19:02 -0700
committerKaz Kylheku <kaz@kylheku.com>2020-10-05 06:19:02 -0700
commit2d4d37907eb060fc23cc4a9f8ebf6b577db3a18b (patch)
treef3d7a0a522c2ccacde21ab944fb53ec0c7363c85
parent77f92bd8b4cb96ddae97b2cdec2427fd4c16c6ee (diff)
downloadtxr-2d4d37907eb060fc23cc4a9f8ebf6b577db3a18b.tar.gz
txr-2d4d37907eb060fc23cc4a9f8ebf6b577db3a18b.tar.bz2
txr-2d4d37907eb060fc23cc4a9f8ebf6b577db3a18b.zip
New functions trim-left and trim-right.
* regex.c (trim_left, trim_right): New static functions. (regex_init): New intrinsics registered. * tests/015/trim.tl, tests/015/trim.expected: New files. * txr.1: Documented.
-rw-r--r--regex.c28
-rw-r--r--tests/015/trim.expected0
-rw-r--r--tests/015/trim.tl41
-rw-r--r--txr.171
4 files changed, 140 insertions, 0 deletions
diff --git a/regex.c b/regex.c
index acb2c7a8..27961970 100644
--- a/regex.c
+++ b/regex.c
@@ -3224,6 +3224,32 @@ val count_until_match(val regex, val stream_in)
return scan_until_common(lit("count-until-match"), regex, stream_in, nil, nil);
}
+static val trim_left(val regex, val string)
+{
+ if (regexp(regex)) {
+ val pos = match_regex(string, regex, nil);
+ if (pos)
+ return sub_str(string, pos, t);
+ } else if (starts_with(regex, string, nil, nil)) {
+ return sub_str(string, length(regex), t);
+ }
+
+ return string;
+}
+
+static val trim_right(val regex, val string)
+{
+ if (regexp(regex)) {
+ val pos = match_regex_right(string, regex, nil);
+ if (pos)
+ return sub_str(string, zero, minus(length(string), pos));
+ } else if (ends_with(regex, string, nil, nil)) {
+ return sub_str(string, zero, minus(length(string), length(regex)));
+ }
+
+ return string;
+}
+
static char_set_t *create_wide_cs(void)
{
#ifdef FULL_UNICODE
@@ -3350,6 +3376,8 @@ void regex_init(void)
reg_fun(intern(lit("fr^"), user_package), func_n2o(regex_range_left_fun, 1));
reg_fun(intern(lit("fr$"), user_package), func_n2o(regex_range_right_fun, 1));
reg_fun(intern(lit("frr"), user_package), func_n3o(regex_range_search_fun, 1));
+ reg_fun(intern(lit("trim-left"), user_package), func_n2(trim_left));
+ reg_fun(intern(lit("trim-right"), user_package), func_n2(trim_right));
init_special_char_sets();
}
diff --git a/tests/015/trim.expected b/tests/015/trim.expected
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/015/trim.expected
diff --git a/tests/015/trim.tl b/tests/015/trim.tl
new file mode 100644
index 00000000..da1fc0c1
--- /dev/null
+++ b/tests/015/trim.tl
@@ -0,0 +1,41 @@
+(load "../common")
+
+(mtest
+ (trim-left "" "") ""
+ (trim-left 1 "") :error
+ (trim-left "" 1) :error
+ (trim-left 1 1) :error)
+
+(mtest
+ (trim-left "" "abc") "abc"
+ (trim-left "a" "abc") "bc"
+ (trim-left "ab" "abc") "c"
+ (trim-left "abc" "abc") ""
+ (trim-left "abcd" "abc") "abc"
+ (trim-left "z" "abc") "abc")
+
+(mtest
+ (trim-left #// "abc") "abc"
+ (trim-left #/./ "abc") "bc"
+ (trim-left #/../ "abc") "c"
+ (trim-left #/.../ "abc") ""
+ (trim-left #/.*/ "abc") ""
+ (trim-left #/..../ "abc") "abc"
+ (trim-left #/z/ "abc") "abc")
+
+(mtest
+ (trim-right "" "abc") "abc"
+ (trim-right "c" "abc") "ab"
+ (trim-right "bc" "abc") "a"
+ (trim-right "abc" "abc") ""
+ (trim-right "xabc" "abc") "abc"
+ (trim-right "z" "abc") "abc")
+
+(mtest
+ (trim-right #// "abc") "abc"
+ (trim-right #/./ "abc") "ab"
+ (trim-right #/../ "abc") "a"
+ (trim-right #/.../ "abc") ""
+ (trim-right #/.*/ "abc") ""
+ (trim-right #/..../ "abc") "abc"
+ (trim-right #/z/ "abc") "abc")
diff --git a/txr.1 b/txr.1
index 8991fed4..9637ab8d 100644
--- a/txr.1
+++ b/txr.1
@@ -45689,6 +45689,77 @@ is a compiled regular expression
object. For any other object type, it returns
.codn nil .
+.coNP Functions @ trim-left and @ trim-right
+.synb
+.mets (trim-left >> { regex | << prefix } << string )
+.mets (trim-right >> { regex | << suffix } << string )
+.syne
+.desc
+The
+.code trim-left
+and
+.code trim-right
+functions return a new string, equivalent to
+.meta string
+with a leading or trailing portion removed.
+
+If the first argument is a regular expression
+.metn regex ,
+then, respectively,
+.code trim-left
+and
+.code trim-right
+find a prefix or suffix of
+.meta string
+which matches the regular expression.
+If there is no match, or if the match is empty, then
+.meta string
+is returned. Otherwise, a copy of
+.meta string
+is returned in which the matching characters are removed.
+If
+.meta regex
+matches all of
+.meta string
+then the empty string is returned.
+
+If the first argument is a character string, then it is treated
+as if it were a regular expression match for that literal
+sequence of characters. Thus,
+.code trim-left
+interprets that string as a
+.meta prefix
+to be removed, and
+.code trim-right
+as a
+.metn suffix .
+If
+.meta string
+starts with
+.metn prefix ,
+then
+.code trim-left
+returns a copy of
+.meta string
+with
+.meta prefix
+removed. Otherwise,
+.meta string
+is returned.
+Likewise, if
+.meta string
+ends with
+.metn suffix ,
+then
+.code trim-right
+returns a copy of
+.meta string
+with
+.meta suffix
+removed. Otherwise,
+.meta string
+is returned.
+
.coNP Function @ regex-compile
.synb
.mets (regex-compile < form-or-string <> [ error-stream ])