diff options
-rw-r--r-- | eval.c | 2 | ||||
-rw-r--r-- | lib.c | 36 | ||||
-rw-r--r-- | lib.h | 2 | ||||
-rw-r--r-- | tests/015/split.tl | 39 | ||||
-rw-r--r-- | txr.1 | 37 |
5 files changed, 103 insertions, 13 deletions
@@ -7217,7 +7217,7 @@ void eval_init(void) reg_fun(intern(lit("sub-str"), user_package), func_n3o(sub_str, 1)); reg_fun(intern(lit("replace-str"), user_package), func_n4o(replace_str, 2)); reg_fun(intern(lit("cat-str"), user_package), func_n2o(cat_str, 1)); - reg_fun(intern(lit("split-str"), user_package), func_n3o(split_str_keep, 2)); + reg_fun(intern(lit("split-str"), user_package), func_n4o(split_str_keep, 2)); reg_fun(intern(lit("spl"), user_package), func_n3o(spl, 2)); reg_fun(intern(lit("split-str-set"), user_package), func_n2(split_str_set)); reg_fun(intern(lit("sspl"), user_package), func_n2(sspl)); @@ -5735,10 +5735,18 @@ val fmt_join(struct args *args) return join_with(nil, args); } -val split_str_keep(val str, val sep, val keep_sep) +val split_str_keep(val str, val sep, val keep_sep_opt, val count_opt) { val self = lit("split-str"); - keep_sep = default_null_arg(keep_sep); + val keep_sep = default_null_arg(keep_sep_opt); + val count = default_null_arg(count_opt); + cnum cnt = c_num(if3(count, count, negone), self); + + if (count && cnt < 0) + uw_throwf(error_s, lit("~a: count must be nonnegative"), self, nao); + + if (count == zero) + return cons(str, nil); if (regexp(sep)) { list_collect_decl (out, iter); @@ -5758,6 +5766,10 @@ val split_str_keep(val str, val sep, val keep_sep) pos = plus(pos, len); if (keep_sep) iter = list_collect(iter, sub_str(str, new_pos, pos)); + if (cnt > 0 && --cnt == 0) { + iter = list_collect(iter, sub_str(str, pos, t)); + break; + } continue; } break; @@ -5789,8 +5801,14 @@ val split_str_keep(val str, val sep, val keep_sep) val piece = mkustring(one); init_str(piece, cstr, self); iter = list_collect(iter, piece); - if (keep_sep && *(cstr+1)) - iter = list_collect(iter, null_string); + if (*(cstr + 1)) { + if (keep_sep) + iter = list_collect(iter, null_string); + if (cnt > 0 && --cnt == 0) { + iter = list_collect(iter, string(cstr + 1)); + break; + } + } } gc_hint(str); @@ -5817,6 +5835,10 @@ val split_str_keep(val str, val sep, val keep_sep) cstr += len_sep; if (keep_sep) iter = list_collect(iter, sep); + if (cnt > 0 && --cnt == 0) { + iter = list_collect(iter, string(cstr)); + break; + } continue; } break; @@ -5833,13 +5855,13 @@ val split_str_keep(val str, val sep, val keep_sep) val spl(val sep, val arg1, val arg2) { return if3(missingp(arg2), - split_str_keep(arg1, sep, arg2), - split_str_keep(arg2, sep, arg1)); + split_str_keep(arg1, sep, arg2, nil), + split_str_keep(arg2, sep, arg1, nil)); } val split_str(val str, val sep) { - return split_str_keep(str, sep, nil); + return split_str_keep(str, sep, nil, nil); } val split_str_set(val str, val set) @@ -925,7 +925,7 @@ val scat3(val s1, val sep, val s2); val join_with(val sep, struct args *args); val fmt_join(struct args *args); val split_str(val str, val sep); -val split_str_keep(val str, val sep, val keep_sep); +val split_str_keep(val str, val sep, val keep_sep_opt, val count_opt); val spl(val sep, val arg1, val arg2); val split_str_set(val str, val set); val sspl(val set, val str); diff --git a/tests/015/split.tl b/tests/015/split.tl index e54092c5..8cdf7f04 100644 --- a/tests/015/split.tl +++ b/tests/015/split.tl @@ -217,3 +217,42 @@ (join-with "a" "b") "b" (join-with "--" "b" "c" "d") "b--c--d" (join-with #\- "b" "c" "d") "b-c-d") + +(mtest + (split-str "abc" "" : 0) ("abc") + (split-str "abc" "" : 1) ("a" "bc") + (split-str "abc" "" : 2) ("a" "b" "c") + (split-str "abc" "" : 3) ("a" "b" "c") + (split-str "abc" "" : -1) :error) + +(mtest + (split-str "abc" "" t 0) ("abc") + (split-str "abc" "" t 1) ("a" "" "bc") + (split-str "abc" "" t 2) ("a" "" "b" "" "c") + (split-str "abc" "" t 3) ("a" "" "b" "" "c")) + +(mtest + (split-str "a,b,c" "," : 0) ("a,b,c") + (split-str "a,b,c" "," : 1) ("a" "b,c") + (split-str "a,b,c" "," : 2) ("a" "b" "c") + (split-str "a,b,c" "," : 3) ("a" "b" "c")) + +(mtest + (split-str "a,b,c" "," t 0) ("a,b,c") + (split-str "a,b,c" "," t 1) ("a" "," "b,c") + (split-str "a,b,c" "," t 2) ("a" "," "b" "," "c") + (split-str "a,b,c" "," t 3) ("a" "," "b" "," "c")) + +(mtest + (split-str "a12b34c567d" #/[0-9]+/ : 0) ("a12b34c567d") + (split-str "a12b34c567d" #/[0-9]+/ : 1) ("a" "b34c567d") + (split-str "a12b34c567d" #/[0-9]+/ : 2) ("a" "b" "c567d") + (split-str "a12b34c567d" #/[0-9]+/ : 3) ("a" "b" "c" "d") + (split-str "a12b34c567d" #/[0-9]+/ : 4) ("a" "b" "c" "d")) + +(mtest + (split-str "a12b34c567d" #/[0-9]+/ t 0) ("a12b34c567d") + (split-str "a12b34c567d" #/[0-9]+/ t 1) ("a" "12" "b34c567d") + (split-str "a12b34c567d" #/[0-9]+/ t 2) ("a" "12" "b" "34" "c567d") + (split-str "a12b34c567d" #/[0-9]+/ t 3) ("a" "12" "b" "34" "c" "567" "d") + (split-str "a12b34c567d" #/[0-9]+/ t 4) ("a" "12" "b" "34" "c" "567" "d")) @@ -25341,7 +25341,7 @@ string, in order. .coNP Function @ split-str .synb -.mets (split-str < string < sep <> [ keep-between ]) +.mets (split-str < string < sep >> [ keep-between <> [ count ]]) .syne .desc The @@ -25356,6 +25356,14 @@ or a regular expression. It determines the separator character sequences within .metn string . +The following describes the behavior of +.code split-str +in the case when the integer parameter +.meta count +is omitted. The semantics of +.meta count +are then given. + All non-overlapping matches for .meta sep within @@ -25449,6 +25457,25 @@ last character, whereas does not recognize empty separators at these outer limits of the string. +If the +.meta count +parameter is present, it must be a non-negative integer. This value +specifies the maximum number of pieces of the input +.meta string +which are extracted by the splitting process. The returned list +consists of these pieces, followed by the remainder of the string, if +the remainder is nonempty. If +.meta keep-sep +is true, then separators appear between the pieces, and if the remainder +piece is present, the separator between the last piece and the remainder +is included. +If +.meta count +is zero, then +.code split-str +returns a list of one element, which is +.metn string . + .coNP Function @ spl .synb .mets (spl < sep <> [ keep-between ] << string ) @@ -70512,7 +70539,7 @@ into the target directory whose path is given by The target directory must exist. -For source each path in +For each source path in .metn from-list , the .code copy-files @@ -70612,9 +70639,11 @@ Propagate the permissions of all objects under onto their .meta to-path counterparts. In the absence of this option, the copied objects -receive permissions with are calculated by applying the +receive the same permissions as a newly created files. +On POSIX systems this means: readable and writable to the owner, +group and others, by default, subject to the .code umask -of the calling process to the maximally liberal. +that is in effect. .IP :times Propagate the modification and access time stamps of all objects under .meta from-path |