diff --git a/shapes3d.scad b/shapes3d.scad index 1af3154..4cf94ba 100644 --- a/shapes3d.scad +++ b/shapes3d.scad @@ -2080,7 +2080,7 @@ module atext(text, h=1, size=9, font="Courier", anchor="baseline", spin=0, orien anch = !any([for (c=anchor) c=="["])? anchor : let( parts = str_split(str_split(str_split(anchor,"]")[0],"[")[1],","), - vec = [for (p=parts) str_float(str_strip_leading(p," "))] + vec = [for (p=parts) str_float(str_strip(p," ",start=true))] ) vec; ha = anchor=="baseline"? "left" : anchor==anch && is_string(anchor)? "center" : diff --git a/strings.scad b/strings.scad index 57f92ef..26ec444 100644 --- a/strings.scad +++ b/strings.scad @@ -6,7 +6,7 @@ ////////////////////////////////////////////////////////////////////// -// Section: Extracting Substrings +// Section: Extracting substrings // Function: substr() // Usage: @@ -48,69 +48,256 @@ function suffix(str,len) = +// Section: String Searching -// Section: Checking character class -// Function: is_lower() +// Function: str_find() // Usage: -// x = is_lower(s); +// str_find(str,pattern,[last],[all],[start]) // Description: -// Returns true if all the characters in the given string are lowercase letters. (a-z) -function is_lower(s) = - assert(is_string(s)) - s==""? false : - len(s)>1? all([for (v=s) is_lower(v)]) : - let(v = ord(s[0])) (v>=ord("a") && v<=ord("z")); +// Searches input string `str` for the string `pattern` and returns the index or indices of the matches in `str`. +// By default `str_find()` returns the index of the first match in `str`. If `last` is true then it returns the index of the last match. +// If the pattern is the empty string the first match is at zero and the last match is the last character of the `str`. +// If `start` is set then the search begins at index start, working either forward and backward from that position. If you set `start` +// and `last` is true then the search will find the pattern if it begins at index `start`. If no match exists, returns `undef`. +// If you set `all` to true then `str_find()` returns all of the matches in a list, or an empty list if there are no matches. +// Arguments: +// str = String to search. +// pattern = string pattern to search for +// last = set to true to return the last match. Default: false +// all = set to true to return all matches as a list. Overrides last. Default: false +// start = index where the search starts +// Example: +// str_find("abc123def123abc","123"); // Returns 3 +// str_find("abc123def123abc","b"); // Returns 1 +// str_find("abc123def123abc","1234"); // Returns undef +// str_find("abc",""); // Returns 0 +// str_find("abc123def123", "123", start=4); // Returns 9 +// str_find("abc123def123abc","123",last=true); // Returns 9 +// str_find("abc123def123abc","b",last=true); // Returns 13 +// str_find("abc123def123abc","1234",last=true); // Returns undef +// str_find("abc","",last=true); // Returns 3 +// str_find("abc123def123", "123", start=8, last=true)); // Returns 3 +// str_find("abc123def123abc","123",all=true); // Returns [3,9] +// str_find("abc123def123abc","b",all=true); // Returns [1,13] +// str_find("abc123def123abc","1234",all=true); // Returns [] +// str_find("abc","",all=true); // Returns [0,1,2] +function str_find(str,pattern,start=undef,last=false,all=false) = + all? _str_find_all(str,pattern) : + let( start = first_defined([start,last?len(str)-len(pattern):0]) ) + pattern==""? start : + last? _str_find_last(str,pattern,start) : + _str_find_first(str,pattern,len(str)-len(pattern),start); + +function _str_find_first(str,pattern,max_sindex,sindex) = + sindex<=max_sindex && !_str_cmp(str,sindex, pattern)? + _str_find_first(str,pattern,max_sindex,sindex+1) : + (sindex <= max_sindex ? sindex : undef); + +function _str_find_last(str,pattern,sindex) = + sindex>=0 && !_str_cmp(str,sindex, pattern)? + _str_find_last(str,pattern,sindex-1) : + (sindex >=0 ? sindex : undef); + +function _str_find_all(str,pattern) = + pattern == "" ? count(len(str)) : + [for(i=[0:1:len(str)-len(pattern)]) if (_str_cmp(str,i,pattern)) i]; + +// _str_cmp(str,sindex,pattern) +// returns true if the string pattern matches the string +// starting at index position sindex in the string. +// +// This is carefully optimized for speed. Precomputing the length +// cuts run time in half when the string is long. Two other string +// comparison methods were slower. +function _str_cmp(str,sindex,pattern) = + len(str)-sindex 1? all([for (v=s) is_upper(v)]) : - let(v = ord(s[0])) (v>=ord("A") && v<=ord("Z")); +// Returns true if the input string `str` starts with the specified string pattern, `pattern`. +// Otherwise returns false. +// Arguments: +// str = String to search. +// pattern = String pattern to search for. +// Example: +// starts_with("abcdef","abc"); // Returns true +// starts_with("abcdef","def"); // Returns false +// starts_with("abcdef",""); // Returns true +function starts_with(str,pattern) = _str_cmp(str,0,pattern); -// Function: is_digit() +// Function: ends_with() // Usage: -// x = is_digit(s); +// ends_with(str,pattern) // Description: -// Returns true if all the characters in the given string are digits. (0-9) -function is_digit(s) = - assert(is_string(s)) - s==""? false : - len(s)>1? all([for (v=s) is_digit(v)]) : - let(v = ord(s[0])) (v>=ord("0") && v<=ord("9")); +// Returns true if the input string `str` ends with the specified string pattern, `pattern`. +// Otherwise returns false. +// Arguments: +// str = String to search. +// pattern = String pattern to search for. +// Example: +// ends_with("abcdef","def"); // Returns true +// ends_with("abcdef","de"); // Returns false +// ends_with("abcdef",""); // Returns true +function ends_with(str,pattern) = _str_cmp(str,len(str)-len(pattern),pattern); -// Function: is_hexdigit() + +// Function: str_split() // Usage: -// x = is_hexdigit(s); +// str_split(str, sep, [keep_nulls]) // Description: -// Returns true if all the characters in the given string are valid hexadecimal digits. (0-9 or a-f or A-F)) -function is_hexdigit(s) = - assert(is_string(s)) - s==""? false : - len(s)>1? all([for (v=s) is_hexdigit(v)]) : - let(v = ord(s[0])) - (v>=ord("0") && v<=ord("9")) || - (v>=ord("A") && v<=ord("F")) || - (v>=ord("a") && v<=ord("f")); +// Breaks an input string into substrings using a separator or list of separators. If keep_nulls is true +// then two sequential separator characters produce an empty string in the output list. If keep_nulls is false +// then no empty strings are included in the output list. +// . +// If sep is a single string then each character in sep is treated as a delimiting character and the input string is +// split at every delimiting character. Empty strings can occur whenever two delimiting characters are sequential. +// If sep is a list of strings then the input string is split sequentially using each string from the list in order. +// If keep_nulls is true then the output will have length equal to `len(sep)+1`, possibly with trailing null strings +// if the string runs out before the separator list. +// Arguments: +// str = String to split. +// sep = a string or list of strings to use for the separator +// keep_nulls = boolean value indicating whether to keep null strings in the output list. Default: true +// Example: +// str_split("abc+def-qrs*iop","*-+"); // Returns ["abc", "def", "qrs", "iop"] +// str_split("abc+*def---qrs**iop+","*-+");// Returns ["abc", "", "def", "", "", "qrs", "", "iop", ""] +// str_split("abc def"," "); // Returns ["abc", "", "", "", "", "", "def"] +// str_split("abc def"," ",keep_nulls=false); // Returns ["abc", "def"] +// str_split("abc+def-qrs*iop",["+","-","*"]); // Returns ["abc", "def", "qrs", "iop"] +// str_split("abc+def-qrs*iop",["-","+","*"]); // Returns ["abc+def", "qrs*iop", "", ""] +function str_split(str,sep,keep_nulls=true) = + !keep_nulls ? _remove_empty_strs(str_split(str,sep,keep_nulls=true)) : + is_list(sep) ? _str_split_recurse(str,sep,i=0,result=[]) : + let( cutpts = concat([-1],sort(flatten(search(sep, str,0))),[len(str)])) + [for(i=[0:len(cutpts)-2]) substr(str,cutpts[i]+1,cutpts[i+1]-cutpts[i]-1)]; + +function _str_split_recurse(str,sep,i,result) = + i == len(sep) ? concat(result,[str]) : + let( + pos = search(sep[i], str), + end = pos==[] ? len(str) : pos[0] + ) + _str_split_recurse( + substr(str,end+1), + sep, i+1, + concat(result, [substr(str,0,end)]) + ); + +function _remove_empty_strs(list) = + list_remove(list, search([""], list,0)[0]); -// Function: is_letter() + +// Section: String modification + + +// Function: str_join() // Usage: -// x = is_letter(s); +// str_join(list, [sep]) // Description: -// Returns true if all the characters in the given string are standard ASCII letters. (A-Z or a-z) -function is_letter(s) = - assert(is_string(s)) - s==""? false : - all([for (v=s) is_lower(v) || is_upper(v)]); +// Returns the concatenation of a list of strings, optionally with a +// separator string inserted between each string on the list. +// Arguments: +// list = list of strings to concatenate +// sep = separator string to insert. Default: "" +// Example: +// str_join(["abc","def","ghi"]); // Returns "abcdefghi" +// str_join(["abc","def","ghi"], " + "); // Returns "abc + def + ghi" +function str_join(list,sep="",_i=0, _result="") = + _i >= len(list)-1 ? (_i==len(list) ? _result : str(_result,list[_i])) : + str_join(list,sep,_i+1,str(_result,list[_i],sep)); + + + + +// Function: str_strip() +// Usage: +// str_strip(s,c,[start],[end]); +// Description: +// Takes a string `s` and strips off all leading and/or trailing characters that exist in string `c`. +// By default strips both leading and trailing characters. If you set start or end to true then +// it will strip only the leading or trailing characters respectively. If you set start +// or end to false then it will strip only lthe trailing or leading characters. +// Arguments: +// s = The string to strip leading or trailing characters from. +// c = The string of characters to strip. +// start = if true then strip leading characters +// end = if true then strip trailing characters +// Example: +// str_strip("--##--123--##--","#-"); // Returns: "123" +// str_strip("--##--123--##--","-"); // Returns: "##--123--##" +// str_strip("--##--123--##--","#"); // Returns: "--##--123--##--" +// str_strip("--##--123--##--","#-",end=true); // Returns: "--##--123" +// str_strip("--##--123--##--","-",end=true); // Returns: "--##--123--##" +// str_strip("--##--123--##--","#",end=true); // Returns: "--##--123--##--" +// str_strip("--##--123--##--","#-",start=true); // Returns: "123--##--" +// str_strip("--##--123--##--","-",start=true); // Returns: "##--123--##--" +// str_strip("--##--123--##--","#",start=true); // Returns: "--##--123--##--" + +function _str_count_leading(s,c,_i=0) = + (_i>=len(s)||!in_list(s[_i],[each c]))? _i : + _str_count_leading(s,c,_i=_i+1); + +function _str_count_trailing(s,c,_i=0) = + (_i>=len(s)||!in_list(s[len(s)-1-_i],[each c]))? _i : + _str_count_trailing(s,c,_i=_i+1); + +function str_strip(s,c,start,end) = + let( + nstart = (is_undef(start) && !end) ? true : start, + nend = (is_undef(end) && !start) ? true : end, + startind = nstart ? _str_count_leading(s,c) : 0, + endind = len(s) - (nend ? _str_count_trailing(s,c) : 0) + ) + substr(s,startind, endind-startind); + + + +// Function: str_pad() +// Usage: +// padded = str_pad(str, length, char, [left]); +// Description: +// Pad the given string `str` with to length `length` with the specified character, +// which must be a length 1 string. If left is true then pad on the left, otherwise +// pad on the right. If the string is longer than the specified length the full string +// is returned unchanged. +// Arguments: +// str = string to pad +// length = length to pad to +// char = character to pad with. Default: " " (space) +// left = if true, pad on the left side. Default: false +function str_pad(str,length,char=" ",left=false) = + assert(is_str(str)) + assert(is_str(char) && len(char)==1, "char must be a single character string") + assert(is_bool(left)) + let( + padding = str_join(repeat(char,length-len(str))) + ) + left ? str(padding,str) : str(str,padding); + + + +// Function: str_replace_char() +// Usage: +// newstr = str_replace_char(str, char, replace) +// Description: +// Replace every occurence of `char` in the input string with the string `replace` which +// can be any string. +function str_replace_char(str,char,replace) = + assert(is_str(str)) + assert(is_str(char) && len(char)==1, "Search pattern 'char' must be a single character string") + assert(is_str(replace)) + str_join([for(c=str) c==char ? replace : c]); // Function: downcase() @@ -143,6 +330,7 @@ function upcase(str) = + // Section: Converting strings to numbers // Function: str_int() @@ -365,7 +553,7 @@ function fmt_float(f,sig=12) = ) str_join([ str(whole), - str_strip_trailing( + str_strip(end=true, str_join([ ".", fmt_int(part, mindigits=mv) @@ -532,264 +720,72 @@ module echofmt(fmt, vals) { } -// Section: Uncategorized string functions -// Function: str_join() +// Section: Checking character class + +// Function: is_lower() // Usage: -// str_join(list, [sep]) +// x = is_lower(s); // Description: -// Returns the concatenation of a list of strings, optionally with a -// separator string inserted between each string on the list. -// Arguments: -// list = list of strings to concatenate -// sep = separator string to insert. Default: "" -// Example: -// str_join(["abc","def","ghi"]); // Returns "abcdefghi" -// str_join(["abc","def","ghi"], " + "); // Returns "abc + def + ghi" -function str_join(list,sep="",_i=0, _result="") = - _i >= len(list)-1 ? (_i==len(list) ? _result : str(_result,list[_i])) : - str_join(list,sep,_i+1,str(_result,list[_i],sep)); +// Returns true if all the characters in the given string are lowercase letters. (a-z) +function is_lower(s) = + assert(is_string(s)) + s==""? false : + len(s)>1? all([for (v=s) is_lower(v)]) : + let(v = ord(s[0])) (v>=ord("a") && v<=ord("z")); - - -// Function: str_split() +// Function: is_upper() // Usage: -// str_split(str, sep, [keep_nulls]) +// x = is_upper(s); // Description: -// Breaks an input string into substrings using a separator or list of separators. If keep_nulls is true -// then two sequential separator characters produce an empty string in the output list. If keep_nulls is false -// then no empty strings are included in the output list. -// . -// If sep is a single string then each character in sep is treated as a delimiting character and the input string is -// split at every delimiting character. Empty strings can occur whenever two delimiting characters are sequential. -// If sep is a list of strings then the input string is split sequentially using each string from the list in order. -// If keep_nulls is true then the output will have length equal to `len(sep)+1`, possibly with trailing null strings -// if the string runs out before the separator list. -// Arguments: -// str = String to split. -// sep = a string or list of strings to use for the separator -// keep_nulls = boolean value indicating whether to keep null strings in the output list. Default: true -// Example: -// str_split("abc+def-qrs*iop","*-+"); // Returns ["abc", "def", "qrs", "iop"] -// str_split("abc+*def---qrs**iop+","*-+");// Returns ["abc", "", "def", "", "", "qrs", "", "iop", ""] -// str_split("abc def"," "); // Returns ["abc", "", "", "", "", "", "def"] -// str_split("abc def"," ",keep_nulls=false); // Returns ["abc", "def"] -// str_split("abc+def-qrs*iop",["+","-","*"]); // Returns ["abc", "def", "qrs", "iop"] -// str_split("abc+def-qrs*iop",["-","+","*"]); // Returns ["abc+def", "qrs*iop", "", ""] -function str_split(str,sep,keep_nulls=true) = - !keep_nulls ? _remove_empty_strs(str_split(str,sep,keep_nulls=true)) : - is_list(sep) ? _str_split_recurse(str,sep,i=0,result=[]) : - let( cutpts = concat([-1],sort(flatten(search(sep, str,0))),[len(str)])) - [for(i=[0:len(cutpts)-2]) substr(str,cutpts[i]+1,cutpts[i+1]-cutpts[i]-1)]; - -function _str_split_recurse(str,sep,i,result) = - i == len(sep) ? concat(result,[str]) : - let( - pos = search(sep[i], str), - end = pos==[] ? len(str) : pos[0] - ) - _str_split_recurse( - substr(str,end+1), - sep, i+1, - concat(result, [substr(str,0,end)]) - ); - -function _remove_empty_strs(list) = - list_remove(list, search([""], list,0)[0]); +// Returns true if all the characters in the given string are uppercase letters. (A-Z) +function is_upper(s) = + assert(is_string(s)) + s==""? false : + len(s)>1? all([for (v=s) is_upper(v)]) : + let(v = ord(s[0])) (v>=ord("A") && v<=ord("Z")); -// _str_cmp(str,sindex,pattern) -// returns true if the string pattern matches the string -// starting at index position sindex in the string. -// -// This is carefully optimized for speed. Precomputing the length -// cuts run time in half when the string is long. Two other string -// comparison methods were slower. -function _str_cmp(str,sindex,pattern) = - len(str)-sindex =0 && !_str_cmp(str,sindex, pattern)? - _str_find_last(str,pattern,sindex-1) : - (sindex >=0 ? sindex : undef); - -function _str_find_all(str,pattern) = - pattern == "" ? count(len(str)) : - [for(i=[0:1:len(str)-len(pattern)]) if (_str_cmp(str,i,pattern)) i]; +// Returns true if all the characters in the given string are digits. (0-9) +function is_digit(s) = + assert(is_string(s)) + s==""? false : + len(s)>1? all([for (v=s) is_digit(v)]) : + let(v = ord(s[0])) (v>=ord("0") && v<=ord("9")); -// Function: starts_with() +// Function: is_hexdigit() // Usage: -// starts_with(str,pattern) +// x = is_hexdigit(s); // Description: -// Returns true if the input string `str` starts with the specified string pattern, `pattern`. -// Otherwise returns false. -// Arguments: -// str = String to search. -// pattern = String pattern to search for. -// Example: -// starts_with("abcdef","abc"); // Returns true -// starts_with("abcdef","def"); // Returns false -// starts_with("abcdef",""); // Returns true -function starts_with(str,pattern) = _str_cmp(str,0,pattern); +// Returns true if all the characters in the given string are valid hexadecimal digits. (0-9 or a-f or A-F)) +function is_hexdigit(s) = + assert(is_string(s)) + s==""? false : + len(s)>1? all([for (v=s) is_hexdigit(v)]) : + let(v = ord(s[0])) + (v>=ord("0") && v<=ord("9")) || + (v>=ord("A") && v<=ord("F")) || + (v>=ord("a") && v<=ord("f")); -// Function: ends_with() +// Function: is_letter() // Usage: -// ends_with(str,pattern) +// x = is_letter(s); // Description: -// Returns true if the input string `str` ends with the specified string pattern, `pattern`. -// Otherwise returns false. -// Arguments: -// str = String to search. -// pattern = String pattern to search for. -// Example: -// ends_with("abcdef","def"); // Returns true -// ends_with("abcdef","de"); // Returns false -// ends_with("abcdef",""); // Returns true -function ends_with(str,pattern) = _str_cmp(str,len(str)-len(pattern),pattern); +// Returns true if all the characters in the given string are standard ASCII letters. (A-Z or a-z) +function is_letter(s) = + assert(is_string(s)) + s==""? false : + all([for (v=s) is_lower(v) || is_upper(v)]); -function _str_count_leading(s,c,_i=0) = - (_i>=len(s)||!in_list(s[_i],[each c]))? _i : - _str_count_leading(s,c,_i=_i+1); - -function _str_count_trailing(s,c,_i=0) = - (_i>=len(s)||!in_list(s[len(s)-1-_i],[each c]))? _i : - _str_count_trailing(s,c,_i=_i+1); - - -// Function: str_strip_leading() -// Usage: -// str_strip_leading(s,c); -// Description: -// Takes a string `s` and strips off all leading characters that exist in string `c`. -// Arguments: -// s = The string to strip leading characters from. -// c = The string of characters to strip. -// Example: -// str_strip_leading("--##--123--##--","#-"); // Returns: "123--##--" -// str_strip_leading("--##--123--##--","-"); // Returns: "##--123--##--" -// str_strip_leading("--##--123--##--","#"); // Returns: "--##--123--##--" -function str_strip_leading(s,c) = substr(s,pos=_str_count_leading(s,c)); - - -// Function: str_strip_trailing() -// Usage: -// str_strip_trailing(s,c); -// Description: -// Takes a string `s` and strips off all trailing characters that exist in string `c`. -// Arguments: -// s = The string to strip trailing characters from. -// c = The string of characters to strip. -// Example: -// str_strip_trailing("--##--123--##--","#-"); // Returns: "--##--123" -// str_strip_trailing("--##--123--##--","-"); // Returns: "--##--123--##" -// str_strip_trailing("--##--123--##--","#"); // Returns: "--##--123--##--" -function str_strip_trailing(s,c) = substr(s,len=len(s)-_str_count_trailing(s,c)); - - -// Function: str_strip() -// Usage: -// str_strip(s,c); -// Description: -// Takes a string `s` and strips off all leading or trailing characters that exist in string `c`. -// Arguments: -// s = The string to strip leading or trailing characters from. -// c = The string of characters to strip. -// Example: -// str_strip("--##--123--##--","#-"); // Returns: "123" -// str_strip("--##--123--##--","-"); // Returns: "##--123--##" -// str_strip("--##--123--##--","#"); // Returns: "--##--123--##--" -function str_strip(s,c) = str_strip_trailing(str_strip_leading(s,c),c); - - - -// Function: str_pad() -// Usage: -// padded = str_pad(str, length, char, [left]); -// Description: -// Pad the given string `str` with to length `length` with the specified character, -// which must be a length 1 string. If left is true then pad on the left, otherwise -// pad on the right. If the string is longer than the specified length the full string -// is returned unchanged. -// Arguments: -// str = string to pad -// length = length to pad to -// char = character to pad with. Default: " " (space) -// left = if true, pad on the left side. Default: false -function str_pad(str,length,char=" ",left=false) = - assert(is_str(str)) - assert(is_str(char) && len(char)==1, "char must be a single character string") - assert(is_bool(left)) - let( - padding = str_join(repeat(char,length-len(str))) - ) - left ? str(padding,str) : str(str,padding); - - -// Function: str_replace_char() -// Usage: -// newstr = str_replace_char(str, char, replace) -// Description: -// Replace every occurence of `char` in the input string with the string `replace` which -// can be any string. -function str_replace_char(str,char,replace) = - assert(is_str(str)) - assert(is_str(char) && len(char)==1, "Search pattern 'char' must be a single character string") - assert(is_str(replace)) - str_join([for(c=str) c==char ? replace : c]); - diff --git a/tests/test_strings.scad b/tests/test_strings.scad index 5304797..df72263 100644 --- a/tests/test_strings.scad +++ b/tests/test_strings.scad @@ -273,34 +273,35 @@ module test_str_strip() { assert(str_strip("abcdef ", " ") == "abcdef"); assert(str_strip(" abcdef ", " ") == "abcdef"); assert(str_strip(" abcdef ", " ") == "abcdef"); + assert(str_strip("abcdef", " ",start=true) == "abcdef"); + assert(str_strip(" abcdef", " ",start=true) == "abcdef"); + assert(str_strip(" abcdef", " ",start=true) == "abcdef"); + assert(str_strip("abcdef ", " ",start=true) == "abcdef "); + assert(str_strip("abcdef ", " ",start=true) == "abcdef "); + assert(str_strip(" abcdef ", " ",start=true) == "abcdef "); + assert(str_strip(" abcdef ", " ",start=true) == "abcdef "); + assert(str_strip("abcdef", " ",end=true) == "abcdef"); + assert(str_strip(" abcdef", " ",end=true) == " abcdef"); + assert(str_strip(" abcdef", " ",end=true) == " abcdef"); + assert(str_strip("abcdef ", " ",end=true) == "abcdef"); + assert(str_strip("abcdef ", " ",end=true) == "abcdef"); + assert(str_strip(" abcdef ", " ",end=true) == " abcdef"); + assert(str_strip(" abcdef ", " ",end=true) == " abcdef"); + assert(str_strip("123abc321","12") == "3abc3"); + assert(str_strip("123abc321","12",start=true,end=true) == "3abc3"); + assert(str_strip("123abc321","12",start=true,end=false) == "3abc321"); + assert(str_strip("123abc321","12",start=false,end=false) == "123abc321"); + assert(str_strip("123abc321","12",start=false,end=true) == "123abc3"); + assert(str_strip("123abc321","12",start=false) == "123abc3"); + assert(str_strip("123abc321","12",start=true) == "3abc321"); + assert(str_strip("123abc321","12",end=false) == "3abc321"); + assert(str_strip("123abc321","12",end=true) == "123abc3"); + assert(str_strip("abcde","abcde")==""); + assert(str_strip("","abc")==""); } test_str_strip(); -module test_str_strip_leading() { - assert(str_strip_leading("abcdef", " ") == "abcdef"); - assert(str_strip_leading(" abcdef", " ") == "abcdef"); - assert(str_strip_leading(" abcdef", " ") == "abcdef"); - assert(str_strip_leading("abcdef ", " ") == "abcdef "); - assert(str_strip_leading("abcdef ", " ") == "abcdef "); - assert(str_strip_leading(" abcdef ", " ") == "abcdef "); - assert(str_strip_leading(" abcdef ", " ") == "abcdef "); -} -test_str_strip_leading(); - - -module test_str_strip_trailing() { - assert(str_strip_trailing("abcdef", " ") == "abcdef"); - assert(str_strip_trailing(" abcdef", " ") == " abcdef"); - assert(str_strip_trailing(" abcdef", " ") == " abcdef"); - assert(str_strip_trailing("abcdef ", " ") == "abcdef"); - assert(str_strip_trailing("abcdef ", " ") == "abcdef"); - assert(str_strip_trailing(" abcdef ", " ") == " abcdef"); - assert(str_strip_trailing(" abcdef ", " ") == " abcdef"); -} -test_str_strip_trailing(); - - module test_substr() { assert(substr("abcdefg",3,3) == "def"); assert(substr("abcdefg",2) == "cdefg");