2020-03-14 11:23:33 +00:00
//////////////////////////////////////////////////////////////////////
// LibFile: strings.scad
// String manipulation and formatting functions.
2021-01-05 09:20:01 +00:00
// Includes:
// include <BOSL2/std.scad>
2021-12-13 23:48:30 +00:00
// FileGroup: Data Management
// FileSummary: String manipulation functions.
// FileFootnotes: STD=Included in std.scad
2020-03-14 11:23:33 +00:00
//////////////////////////////////////////////////////////////////////
2021-11-21 04:19:54 +00:00
// Section: Extracting substrings
2019-07-05 11:25:55 +00:00
2019-06-12 01:55:39 +00:00
// Function: substr()
2023-04-29 02:23:15 +00:00
// Synopsis: Returns a substring from a string.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2019-06-12 01:55:39 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// newstr = substr(str, [pos], [len]);
2019-06-12 01:55:39 +00:00
// Description:
2023-04-29 02:23:15 +00:00
// Returns a substring from a string start at position `pos` with length `len`, or
// if `len` isn't given, the rest of the string.
2019-06-12 01:55:39 +00:00
// Arguments:
// str = string to operate on
// pos = starting index of substring, or vector of first and last position. Default: 0
2023-04-29 02:23:15 +00:00
// len = length of substring, or omit it to get the rest of the string. If len is zero or less then the emptry string is returned.
2019-06-12 01:55:39 +00:00
// Example:
// substr("abcdefg",3,3); // Returns "def"
// substr("abcdefg",2); // Returns "cdefg"
// substr("abcdefg",len=3); // Returns "abc"
// substr("abcdefg",[2,4]); // Returns "cde"
2019-06-22 17:33:49 +00:00
// substr("abcdefg",len=-2); // Returns ""
function substr ( str , pos = 0 , len = undef ) =
2020-05-30 02:04:34 +00:00
is_list ( pos ) ? _substr ( str , pos [ 0 ] , pos [ 1 ] - pos [ 0 ] + 1 ) :
len = = undef ? _substr ( str , pos , len ( str ) - pos ) :
_substr ( str , pos , len ) ;
2019-06-22 17:33:49 +00:00
2023-04-29 02:23:15 +00:00
function _substr ( str , pos , len , substr = "" ) =
2020-05-30 02:04:34 +00:00
len < = 0 || pos >= len ( str ) ? substr :
_substr ( str , pos + 1 , len - 1 , str ( substr , str [ pos ] ) ) ;
2019-06-12 01:55:39 +00:00
2020-03-14 11:23:33 +00:00
2021-02-17 17:56:20 +00:00
// Function: suffix()
2023-04-29 02:23:15 +00:00
// Synopsis: Returns the last few characters of a string.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2019-06-12 01:55:39 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// newstr = suffix(str,len);
2019-06-12 01:55:39 +00:00
// Description:
2020-06-15 08:24:57 +00:00
// Returns the last `len` characters from the input string `str`.
// If `len` is longer than the length of `str`, then the entirety of `str` is returned.
// Arguments:
// str = The string to get the suffix of.
// len = The number of characters of suffix to get.
function suffix ( str , len ) =
len >= len ( str ) ? str : substr ( str , len ( str ) - len , len ) ;
2019-06-12 01:55:39 +00:00
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Section: String Searching
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Function: str_find()
2023-04-29 02:23:15 +00:00
// Synopsis: Finds a substring in a string.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2019-06-12 01:55:39 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// ind = str_find(str,pattern,[last=],[all=],[start=]);
2019-06-12 01:55:39 +00:00
// Description:
2021-11-21 04:19:54 +00:00
// 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
2022-04-07 21:28:41 +00:00
// ---
2021-11-21 04:19:54 +00:00
// last = set to true to return the last match. Default: false
2023-04-29 02:23:15 +00:00
// all = set to true to return all matches as a list. Overrides last. Default: false
2021-11-21 04:19:54 +00:00
// 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 ) ;
2023-04-29 02:23:15 +00:00
function _str_find_first ( str , pattern , max_sindex , sindex ) =
2022-08-15 00:33:31 +00:00
sindex < = max_sindex && ! substr_match ( str , sindex , pattern ) ?
2021-11-21 04:19:54 +00:00
_str_find_first ( str , pattern , max_sindex , sindex + 1 ) :
( sindex < = max_sindex ? sindex : undef ) ;
2021-11-11 03:47:28 +00:00
2023-04-29 02:23:15 +00:00
function _str_find_last ( str , pattern , sindex ) =
2022-08-15 00:33:31 +00:00
sindex >= 0 && ! substr_match ( str , sindex , pattern ) ?
2021-11-21 04:19:54 +00:00
_str_find_last ( str , pattern , sindex - 1 ) :
( sindex >= 0 ? sindex : undef ) ;
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
function _str_find_all ( str , pattern ) =
pattern = = "" ? count ( len ( str ) ) :
2022-08-15 00:33:31 +00:00
[ for ( i = [ 0 : 1 : len ( str ) - len ( pattern ) ] ) if ( substr_match ( str , i , pattern ) ) i ] ;
// Function: substr_match()
2023-04-29 02:23:15 +00:00
// Synopsis: Returns true if the string `pattern` matches the string `str`.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2022-08-15 00:33:31 +00:00
// Usage
// bool = substr_match(str,start,pattern);
// Description:
// Returns true if the string `pattern` matches the string `str` starting
// at `str[start]`. If the string is too short for the pattern, or
2023-04-29 02:23:15 +00:00
// `start` is out of bounds – either negative or beyond the end of the
// string – then substr_match returns false.
2022-08-15 00:33:31 +00:00
// Arguments:
// str = String to search
// start = Starting index for search in str
// pattern = String pattern to search for
// Examples:
// substr_match("abcde",2,"cd"); // Returns true
// substr_match("abcde",2,"cx"); // Returns false
// substr_match("abcde",2,"cdef"); // Returns false
// substr_match("abcde",-2,"cd"); // Returns false
// substr_match("abcde",19,"cd"); // Returns false
// substr_match("abc",1,""); // Returns true
2021-11-21 04:19:54 +00:00
//
// This is carefully optimized for speed. Precomputing the length
// cuts run time in half when the string is long. Two other string
2023-04-29 02:23:15 +00:00
// comparison methods were slower.
2022-08-15 00:33:31 +00:00
function substr_match ( str , start , pattern ) =
len ( str ) - start < len ( pattern ) ? false
: _substr_match_recurse ( str , start , pattern , len ( pattern ) ) ;
2021-11-21 04:19:54 +00:00
2022-08-15 00:33:31 +00:00
function _substr_match_recurse ( str , sindex , pattern , plen , pindex = 0 , ) =
pindex < plen && pattern [ pindex ] = = str [ sindex ]
? _substr_match_recurse ( str , sindex + 1 , pattern , plen , pindex + 1 )
: ( pindex = = plen ) ;
2021-11-21 04:19:54 +00:00
// Function: starts_with()
2023-04-29 02:23:15 +00:00
// Synopsis: Returns true if the string starts with a given substring.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2021-11-11 03:47:28 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// bool = starts_with(str,pattern);
2021-11-11 03:47:28 +00:00
// Description:
2021-11-21 04:19:54 +00:00
// Returns true if the input string `str` starts with the specified string pattern, `pattern`.
2023-04-29 02:23:15 +00:00
// Otherwise returns false.
2021-11-21 04:19:54 +00:00
// 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
2022-08-15 00:33:31 +00:00
function starts_with ( str , pattern ) = substr_match ( str , 0 , pattern ) ;
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Function: ends_with()
2023-04-29 02:23:15 +00:00
// Synopsis: Returns true if the string ends with a given substring.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2021-11-11 03:47:28 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// bool = ends_with(str,pattern);
2021-11-11 03:47:28 +00:00
// Description:
2021-11-21 04:19:54 +00:00
// Returns true if the input string `str` ends with the specified string pattern, `pattern`.
2023-04-29 02:23:15 +00:00
// Otherwise returns false.
2021-11-21 04:19:54 +00:00
// 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
2022-08-15 00:33:31 +00:00
function ends_with ( str , pattern ) = substr_match ( str , len ( str ) - len ( pattern ) , pattern ) ;
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Function: str_split()
2023-04-29 02:23:15 +00:00
// Synopsis: Splits a longer string wherever a given substring occurs.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2021-11-11 03:47:28 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// string_list = str_split(str, sep, [keep_nulls]);
2021-11-11 03:47:28 +00:00
// Description:
2021-11-21 04:19:54 +00:00
// 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.
2023-04-29 02:23:15 +00:00
// If sep is a list of strings then the input string is split sequentially using each string from the list in order.
2021-11-21 04:19:54 +00:00
// If keep_nulls is true then the output will have length equal to `len(sep)+1`, possibly with trailing null strings
2023-04-29 02:23:15 +00:00
// if the string runs out before the separator list.
2021-11-21 04:19:54 +00:00
// 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 ) ] )
) ;
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
function _remove_empty_strs ( list ) =
list_remove ( list , search ( [ "" ] , list , 0 ) [ 0 ] ) ;
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Section: String modification
// Function: str_join()
2023-04-29 02:23:15 +00:00
// Synopsis: Joints a list of strings into a single string.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2021-11-11 03:47:28 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// str = str_join(list, [sep]);
2021-11-11 03:47:28 +00:00
// Description:
2021-11-21 04:19:54 +00:00
// 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()
2023-04-29 02:23:15 +00:00
// Synopsis: Strips given leading and trailing characters from a string.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2021-11-21 04:19:54 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// str = str_strip(s,c,[start],[end]);
2021-11-21 04:19:54 +00:00
// 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()
2023-04-29 02:23:15 +00:00
// Synopsis: Pads a string to a given length.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2021-11-21 04:19:54 +00:00
// 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
2023-04-29 02:23:15 +00:00
// is returned unchanged.
2021-11-21 04:19:54 +00:00
// 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()
2023-04-29 02:23:15 +00:00
// Synopsis: Replace given chars in a string with another substring.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip()
2021-11-21 04:19:54 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// newstr = str_replace_char(str, char, replace);
2021-11-21 04:19:54 +00:00
// Description:
// Replace every occurence of `char` in the input string with the string `replace` which
2023-04-29 02:23:15 +00:00
// can be any string.
2021-11-21 04:19:54 +00:00
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 ] ) ;
2019-06-12 01:55:39 +00:00
2020-03-14 11:23:33 +00:00
2019-06-12 01:55:39 +00:00
// Function: downcase()
2023-04-29 02:23:15 +00:00
// Synopsis: Lowercases all characters in a string.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip(), upcase(), downcase()
2019-06-12 01:55:39 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// newstr = downcase(str);
2019-06-12 01:55:39 +00:00
// Description:
// Returns the string with the standard ASCII upper case letters A-Z replaced
// by their lower case versions.
// Arguments:
2020-03-14 11:23:33 +00:00
// str = String to convert.
2019-06-12 01:55:39 +00:00
// Example:
// downcase("ABCdef"); // Returns "abcdef"
function downcase ( str ) =
2020-05-30 02:04:34 +00:00
str_join ( [ for ( char = str ) let ( code = ord ( char ) ) code >= 65 && code < = 90 ? chr ( code + 32 ) : char ] ) ;
2019-06-12 01:55:39 +00:00
2020-03-14 11:23:33 +00:00
// Function: upcase()
2023-04-29 02:23:15 +00:00
// Synopsis: Uppercases all characters in a string.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip(), upcase(), downcase()
2020-03-14 11:23:33 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// newstr = upcase(str);
2020-03-14 11:23:33 +00:00
// Description:
// Returns the string with the standard ASCII lower case letters a-z replaced
// by their upper case versions.
// Arguments:
// str = String to convert.
// Example:
// upcase("ABCdef"); // Returns "ABCDEF"
function upcase ( str ) =
2020-05-30 02:04:34 +00:00
str_join ( [ for ( char = str ) let ( code = ord ( char ) ) code >= 97 && code < = 122 ? chr ( code - 32 ) : char ] ) ;
2020-03-14 11:23:33 +00:00
2022-05-15 15:47:44 +00:00
// Section: Random strings
// Function: rand_str()
2023-04-29 02:23:15 +00:00
// Synopsis: Create a randomized string.
// Topics: Strings
// See Also: suffix(), str_find(), substr_match(), starts_with(), ends_with(), str_split(), str_join(), str_strip(), upcase(), downcase()
2022-05-15 15:47:44 +00:00
// Usage:
// str = rand_str(n, [charset], [seed]);
// Description:
// Produce a random string of length `n`. If you give a string `charset` then the
// characters of the random string are drawn from that list, weighted by the number
// of times each character appears in the list. If you do not give a character set
// then the string is generated with characters ranging from 0 to z (based on
2023-04-29 02:23:15 +00:00
// character code).
function rand_str ( n , charset , seed ) =
2022-05-15 15:47:44 +00:00
is_undef ( charset ) ? str_join ( [ for ( c = rand_int ( 48 , 122 , n , seed ) ) chr ( c ) ] )
: str_join ( [ for ( i = rand_int ( 0 , len ( charset ) - 1 , n , seed ) ) charset [ i ] ] ) ;
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
2022-01-11 00:46:51 +00:00
// Section: Parsing strings into numbers
2021-11-11 03:47:28 +00:00
2022-01-11 00:46:51 +00:00
// Function: parse_int()
2023-04-29 02:23:15 +00:00
// Synopsis: Parse an integer from a string.
// Topics: Strings
// See Also: parse_int(), parse_float(), parse_frac(), parse_num()
2019-06-12 01:55:39 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// num = parse_int(str, [base])
2019-06-12 01:55:39 +00:00
// Description:
2023-04-29 02:23:15 +00:00
// Converts a string into an integer with any base up to 16. Returns NaN if
2019-06-12 01:55:39 +00:00
// conversion fails. Digits above 9 are represented using letters A-F in either
2023-04-29 02:23:15 +00:00
// upper case or lower case.
2019-06-12 01:55:39 +00:00
// Arguments:
2020-03-14 11:23:33 +00:00
// str = String to convert.
// base = Base for conversion, from 2-16. Default: 10
2019-06-12 01:55:39 +00:00
// Example:
2022-01-11 00:46:51 +00:00
// parse_int("349"); // Returns 349
// parse_int("-37"); // Returns -37
// parse_int("+97"); // Returns 97
// parse_int("43.9"); // Returns nan
// parse_int("1011010",2); // Returns 90
// parse_int("13",2); // Returns nan
// parse_int("dead",16); // Returns 57005
// parse_int("CEDE", 16); // Returns 52958
// parse_int(""); // Returns 0
function parse_int ( str , base = 10 ) =
2020-05-30 02:04:34 +00:00
str = = undef ? undef :
2023-04-29 02:23:15 +00:00
len ( str ) = = 0 ? 0 :
2020-05-30 02:04:34 +00:00
let ( str = downcase ( str ) )
2022-01-11 00:46:51 +00:00
str [ 0 ] = = "-" ? - _parse_int_recurse ( substr ( str , 1 ) , base , len ( str ) - 2 ) :
str [ 0 ] = = "+" ? _parse_int_recurse ( substr ( str , 1 ) , base , len ( str ) - 2 ) :
_parse_int_recurse ( str , base , len ( str ) - 1 ) ;
2019-06-12 01:55:39 +00:00
2022-01-11 00:46:51 +00:00
function _parse_int_recurse ( str , base , i ) =
2020-05-30 02:04:34 +00:00
let (
digit = search ( str [ i ] , "0123456789abcdef" ) ,
last_digit = digit = = [ ] || digit [ 0 ] >= base ? ( 0 / 0 ) : digit [ 0 ]
2023-04-29 02:23:15 +00:00
) i = = 0 ? last_digit :
2022-01-11 00:46:51 +00:00
_parse_int_recurse ( str , base , i - 1 ) * base + last_digit ;
2019-06-12 01:55:39 +00:00
2020-03-14 11:23:33 +00:00
2022-01-11 00:46:51 +00:00
// Function: parse_float()
2023-04-29 02:23:15 +00:00
// Synopsis: Parse a float from a string.
// Topics: Strings
// See Also: parse_int(), parse_float(), parse_frac(), parse_num()
2019-06-12 01:55:39 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// num = parse_float(str);
2019-06-12 01:55:39 +00:00
// Description:
// Converts a string to a floating point number. Returns NaN if the
// conversion fails.
// Arguments:
2020-03-14 11:23:33 +00:00
// str = String to convert.
2019-06-12 01:55:39 +00:00
// Example:
2022-01-11 00:46:51 +00:00
// parse_float("44"); // Returns 44
// parse_float("3.4"); // Returns 3.4
// parse_float("-99.3332"); // Returns -99.3332
// parse_float("3.483e2"); // Returns 348.3
// parse_float("-44.9E2"); // Returns -4490
// parse_float("7.342e-4"); // Returns 0.0007342
// parse_float(""); // Returns 0
function parse_float ( str ) =
2020-05-30 02:04:34 +00:00
str = = undef ? undef :
len ( str ) = = 0 ? 0 :
in_list ( str [ 1 ] , [ "+" , "-" ] ) ? ( 0 / 0 ) : // Don't allow --3, or +-3
2022-01-11 00:46:51 +00:00
str [ 0 ] = = "-" ? - parse_float ( substr ( str , 1 ) ) :
str [ 0 ] = = "+" ? parse_float ( substr ( str , 1 ) ) :
2020-05-30 02:04:34 +00:00
let ( esplit = str_split ( str , "eE" ) )
2022-01-11 00:46:51 +00:00
len ( esplit ) = = 2 ? parse_float ( esplit [ 0 ] ) * pow ( 10 , parse_int ( esplit [ 1 ] ) ) :
2020-05-30 02:04:34 +00:00
let ( dsplit = str_split ( str , [ "." ] ) )
2022-01-11 00:46:51 +00:00
parse_int ( dsplit [ 0 ] ) + parse_int ( dsplit [ 1 ] ) / pow ( 10 , len ( dsplit [ 1 ] ) ) ;
2019-06-12 01:55:39 +00:00
2020-03-14 11:23:33 +00:00
2022-01-11 00:46:51 +00:00
// Function: parse_frac()
2023-04-29 02:23:15 +00:00
// Synopsis: Parse a float from a fraction string.
// Topics: Strings
// See Also: parse_int(), parse_float(), parse_frac(), parse_num()
2019-06-12 01:55:39 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// num = parse_frac(str,[mixed=],[improper=],[signed=]);
2019-06-12 01:55:39 +00:00
// Description:
2019-06-23 16:51:43 +00:00
// Converts a string fraction to a floating point number. A string fraction has the form `[-][# ][#/#]` where each `#` is one or more of the
2023-04-29 02:23:15 +00:00
// digits 0-9, and there is an optional sign character at the beginning.
2019-06-23 16:51:43 +00:00
// The full form is a sign character and an integer, followed by exactly one space, followed by two more
2023-04-29 02:23:15 +00:00
// integers separated by a "/" character. The leading integer and
2019-06-23 16:51:43 +00:00
// space can be omitted or the trailing fractional part can be omitted. If you set `mixed` to false then the leading integer part is not
// accepted and the input must include a slash. If you set `improper` to false then the fractional part must be a proper fraction, where
// the numerator is smaller than the denominator. If you set `signed` to false then the leading sign character is not permitted.
2023-04-29 02:23:15 +00:00
// The empty string evaluates to zero. Any invalid string evaluates to NaN.
2019-06-12 01:55:39 +00:00
// Arguments:
2020-03-14 11:23:33 +00:00
// str = String to convert.
2022-04-07 21:28:41 +00:00
// ---
2023-04-29 02:23:15 +00:00
// mixed = set to true to accept mixed fractions, false to reject them. Default: true
2019-06-23 16:51:43 +00:00
// improper = set to true to accept improper fractions, false to reject them. Default: true
2023-04-29 02:23:15 +00:00
// signed = set to true to accept a leading sign character, false to reject. Default: true
2019-06-12 01:55:39 +00:00
// Example:
2022-01-11 00:46:51 +00:00
// parse_frac("3/4"); // Returns 0.75
// parse_frac("-77/9"); // Returns -8.55556
// parse_frac("+1/3"); // Returns 0.33333
// parse_frac("19"); // Returns 19
// parse_frac("2 3/4"); // Returns 2.75
// parse_frac("-2 12/4"); // Returns -5
// parse_frac(""); // Returns 0
// parse_frac("3/0"); // Returns inf
// parse_frac("0/0"); // Returns nan
// parse_frac("-77/9",improper=false); // Returns nan
// parse_frac("-2 12/4",improper=false); // Returns nan
// parse_frac("-2 12/4",signed=false); // Returns nan
// parse_frac("-2 12/4",mixed=false); // Returns nan
// parse_frac("2 1/4",mixed=false); // Returns nan
function parse_frac ( str , mixed = true , improper = true , signed = true ) =
2023-03-22 20:11:31 +00:00
str = = undef ? undef
: len ( str ) = = 0 ? 0
: str [ 0 ] = = " " ? NAN
: signed && str [ 0 ] = = "-" ? - parse_frac ( substr ( str , 1 ) , mixed = mixed , improper = improper , signed = false )
: signed && str [ 0 ] = = "+" ? parse_frac ( substr ( str , 1 ) , mixed = mixed , improper = improper , signed = false )
2023-04-29 02:23:15 +00:00
: mixed && ( str_find ( str , " " ) ! = undef || str_find ( str , "/" ) = = undef ) ? // Mixed allowed and there is a space or no slash
2023-03-22 20:11:31 +00:00
let ( whole = str_split ( str , [ " " ] ) )
_parse_int_recurse ( whole [ 0 ] , 10 , len ( whole [ 0 ] ) - 1 ) + parse_frac ( whole [ 1 ] , mixed = false , improper = improper , signed = false )
: let ( split = str_split ( str , "/" ) )
len ( split ) ! = 2 ? NAN
: let (
numerator = _parse_int_recurse ( split [ 0 ] , 10 , len ( split [ 0 ] ) - 1 ) ,
denominator = _parse_int_recurse ( split [ 1 ] , 10 , len ( split [ 1 ] ) - 1 )
)
! improper && numerator >= denominator ? NAN
: denominator < 0 ? NAN
: numerator / denominator ;
2019-06-12 01:55:39 +00:00
2020-03-14 11:23:33 +00:00
2022-01-11 00:46:51 +00:00
// Function: parse_num()
2023-04-29 02:23:15 +00:00
// Synopsis: Parse a float from a decimal or fraction string.
// Topics: Strings
// See Also: parse_int(), parse_float(), parse_frac(), parse_num()
2019-06-12 01:55:39 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// num = parse_num(str);
2019-06-12 01:55:39 +00:00
// Description:
// Converts a string to a number. The string can be either a fraction (two integers separated by a "/") or a floating point number.
// Returns NaN if the conversion fails.
// Example:
2022-01-11 00:46:51 +00:00
// parse_num("3/4"); // Returns 0.75
// parse_num("3.4e-2"); // Returns 0.034
function parse_num ( str ) =
2020-05-30 02:04:34 +00:00
str = = undef ? undef :
2022-01-11 00:46:51 +00:00
let ( val = parse_frac ( str ) )
2020-05-30 02:04:34 +00:00
val = = val ? val :
2022-01-11 00:46:51 +00:00
parse_float ( str ) ;
2019-06-12 01:55:39 +00:00
2019-06-22 17:33:49 +00:00
2022-01-11 00:46:51 +00:00
// Section: Formatting numbers into strings
2020-03-14 11:23:33 +00:00
2022-01-11 00:46:51 +00:00
// Function: format_int()
2023-04-29 02:23:15 +00:00
// Synopsis: Formats an integer into a string, with possible leading zeros.
// Topics: Strings
// See Also: format_int(), format_fixed(), format_float(), format()
2019-06-22 17:33:49 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// str = format_int(i, [mindigits]);
2019-06-22 17:33:49 +00:00
// Description:
2021-11-11 03:47:28 +00:00
// Formats an integer number into a string. This can handle larger numbers than `str()`.
2019-06-22 17:33:49 +00:00
// Arguments:
2021-11-11 03:47:28 +00:00
// i = The integer to make a string of.
// mindigits = If the number has fewer than this many digits, pad the front with zeros until it does. Default: 1.
2019-06-22 17:33:49 +00:00
// Example:
2021-11-11 03:47:28 +00:00
// str(123456789012345); // Returns "1.23457e+14"
2022-01-11 00:46:51 +00:00
// format_int(123456789012345); // Returns "123456789012345"
// format_int(-123456789012345); // Returns "-123456789012345"
function format_int ( i , mindigits = 1 ) =
i < 0 ? str ( "-" , format_int ( - i , mindigits ) ) :
2021-11-11 03:47:28 +00:00
let ( i = floor ( i ) , e = floor ( log ( i ) ) )
i = = 0 ? str_join ( [ for ( j = [ 0 : 1 : mindigits - 1 ] ) "0" ] ) :
str_join (
concat (
[ for ( j = [ 0 : 1 : mindigits - e - 2 ] ) "0" ] ,
[ for ( j = [ e : - 1 : 0 ] ) str ( floor ( i / pow ( 10 , j ) % 10 ) ) ]
)
) ;
2019-06-22 18:50:01 +00:00
2022-01-11 00:46:51 +00:00
// Function: format_fixed()
2023-04-29 02:23:15 +00:00
// Synopsis: Formats a float into a string with a fixed number of decimal places.
// Topics: Strings
// See Also: format_int(), format_fixed(), format_float(), format()
2019-06-22 17:33:49 +00:00
// Usage:
2022-01-11 00:46:51 +00:00
// s = format_fixed(f, [digits]);
2019-06-22 17:33:49 +00:00
// Description:
2021-11-11 03:47:28 +00:00
// Given a floating point number, formats it into a string with the given number of digits after the decimal point.
2019-06-22 17:33:49 +00:00
// Arguments:
2021-11-11 03:47:28 +00:00
// f = The floating point number to format.
// digits = The number of digits after the decimal to show. Default: 6
2022-01-11 00:46:51 +00:00
function format_fixed ( f , digits = 6 ) =
2021-11-11 03:47:28 +00:00
assert ( is_int ( digits ) )
assert ( digits > 0 )
2022-01-11 00:46:51 +00:00
is_list ( f ) ? str ( "[" , str_join ( sep = ", " , [ for ( g = f ) format_fixed ( g , digits = digits ) ] ) , "]" ) :
2021-11-11 03:47:28 +00:00
str ( f ) = = "nan" ? "nan" :
str ( f ) = = "inf" ? "inf" :
2022-01-11 00:46:51 +00:00
f < 0 ? str ( "-" , format_fixed ( - f , digits = digits ) ) :
2021-11-11 03:47:28 +00:00
assert ( is_num ( f ) )
let (
sc = pow ( 10 , digits ) ,
scaled = floor ( f * sc + 0.5 ) ,
whole = floor ( scaled / sc ) ,
part = floor ( scaled - ( whole * sc ) )
2022-01-11 00:46:51 +00:00
) str ( format_int ( whole ) , "." , format_int ( part , digits ) ) ;
2019-06-22 17:33:49 +00:00
2022-01-11 00:46:51 +00:00
// Function: format_float()
2023-04-29 02:23:15 +00:00
// Synopsis: Formats a float into a string with a given number of significant digits.
// Topics: Strings
// See Also: format_int(), format_fixed(), format_float(), format()
2019-06-22 17:33:49 +00:00
// Usage:
2022-08-15 00:33:31 +00:00
// str = format_float(f,[sig]);
2019-06-22 17:33:49 +00:00
// Description:
2021-11-11 03:47:28 +00:00
// Formats the given floating point number `f` into a string with `sig` significant digits.
// Strips trailing `0`s after the decimal point. Strips trailing decimal point.
// If the number can be represented in `sig` significant digits without a mantissa, it will be.
// If given a list of numbers, recursively prints each item in the list, returning a string like `[3,4,5]`
2019-06-22 17:33:49 +00:00
// Arguments:
2021-11-11 03:47:28 +00:00
// f = The floating point number to format.
// sig = The number of significant digits to display. Default: 12
2019-07-05 11:25:55 +00:00
// Example:
2022-01-11 00:46:51 +00:00
// format_float(PI,12); // Returns: "3.14159265359"
// format_float([PI,-16.75],12); // Returns: "[3.14159265359, -16.75]"
function format_float ( f , sig = 12 ) =
2020-05-30 02:04:34 +00:00
assert ( is_int ( sig ) )
assert ( sig > 0 )
2022-01-11 00:46:51 +00:00
is_list ( f ) ? str ( "[" , str_join ( sep = ", " , [ for ( g = f ) format_float ( g , sig = sig ) ] ) , "]" ) :
2020-05-30 02:04:34 +00:00
f = = 0 ? "0" :
str ( f ) = = "nan" ? "nan" :
str ( f ) = = "inf" ? "inf" :
2022-01-11 00:46:51 +00:00
f < 0 ? str ( "-" , format_float ( - f , sig = sig ) ) :
2020-05-30 02:04:34 +00:00
assert ( is_num ( f ) )
let (
e = floor ( log ( f ) ) ,
mv = sig - e - 1
2022-01-11 00:46:51 +00:00
) mv = = 0 ? format_int ( floor ( f + 0.5 ) ) :
( e < - sig / 2 || mv < 0 ) ? str ( format_float ( f * pow ( 10 , - e ) , sig = sig ) , "e" , e ) :
2020-05-30 02:04:34 +00:00
let (
ff = f + pow ( 10 , - mv ) * 0.5 ,
whole = floor ( ff ) ,
part = floor ( ( ff - whole ) * pow ( 10 , mv ) )
)
str_join ( [
str ( whole ) ,
2021-11-21 04:19:54 +00:00
str_strip ( end = true ,
2020-05-30 02:04:34 +00:00
str_join ( [
"." ,
2022-01-11 00:46:51 +00:00
format_int ( part , mindigits = mv )
2020-05-30 02:04:34 +00:00
] ) ,
"0."
)
] ) ;
2019-07-05 11:25:55 +00:00
2022-01-11 00:46:51 +00:00
/// Function: _format_matrix()
/// Usage:
2022-02-22 01:45:57 +00:00
/// _format_matrix(M, [sig], [sep], [eps])
2022-01-11 00:46:51 +00:00
/// Description:
/// Convert a numerical matrix into a matrix of strings where every column
/// is the same width so it will display in neat columns when printed.
/// Values below eps will display as zero. The matrix can include nans, infs
2023-04-29 02:23:15 +00:00
/// or undefs and the rows can be different lengths.
2022-01-11 00:46:51 +00:00
/// Arguments:
/// M = numerical matrix to convert
/// sig = significant digits to display. Default: 4
2022-02-22 01:45:57 +00:00
// sep = number of spaces between columns or a text string to separate columns. Default: 1
2022-01-11 00:46:51 +00:00
/// eps = values smaller than this are shown as zero. Default: 1e-9
2023-04-29 02:23:15 +00:00
function _format_matrix ( M , sig = 4 , sep = 1 , eps = 1e-9 ) =
2021-11-11 03:47:28 +00:00
let (
figure_dash = chr ( 8210 ) ,
space_punc = chr ( 8200 ) ,
space_figure = chr ( 8199 ) ,
2022-02-22 01:45:57 +00:00
sep = is_num ( sep ) && sep >= 0 ? str_join ( repeat ( space_figure , sep ) )
: is_string ( sep ) ? sep
: assert ( false , "Invalid separator: must be a string or positive integer giving number of spaces" ) ,
2021-11-11 03:47:28 +00:00
strarr =
[ for ( row = M )
[ for ( entry = row )
let (
text = is_undef ( entry ) ? "und"
2022-02-22 01:45:57 +00:00
: ! is_num ( entry ) ? str_join ( repeat ( figure_dash , 2 ) )
2021-11-11 03:47:28 +00:00
: abs ( entry ) < eps ? "0" // Replace hyphens with figure dashes
2022-01-11 00:46:51 +00:00
: str_replace_char ( format_float ( entry , sig ) , "-" , figure_dash ) ,
2021-11-11 03:47:28 +00:00
have_dot = is_def ( str_find ( text , "." ) )
)
// If the text lacks a dot we add a space the same width as a dot to
// maintain alignment
str ( have_dot ? "" : space_punc , text )
]
] ,
maxwidth = max ( [ for ( row = M ) len ( row ) ] ) ,
2023-04-29 02:23:15 +00:00
// Find maximum length for each column. Some entries in a column may be missing.
2021-11-11 03:47:28 +00:00
maxlen = [ for ( i = [ 0 : 1 : maxwidth - 1 ] )
max (
[ for ( j = idx ( M ) ) i >= len ( M [ j ] ) ? 0 : len ( strarr [ j ] [ i ] ) ] )
] ,
padded =
[ for ( row = strarr )
str_join ( [ for ( i = idx ( row ) )
let (
extra = ends_with ( row [ i ] , "inf" ) ? 1 : 0
)
2022-02-22 01:45:57 +00:00
str_pad ( row [ i ] , maxlen [ i ] + extra , space_figure , left = true ) ] , sep = sep ) ]
2021-11-11 03:47:28 +00:00
)
padded ;
2020-03-14 11:23:33 +00:00
2022-01-11 00:46:51 +00:00
// Function: format()
2023-04-29 02:23:15 +00:00
// Synopsis: Formats multiple values into a string with a given format.
// Topics: Strings
// See Also: format_int(), format_fixed(), format_float(), format()
2020-03-14 11:23:33 +00:00
// Usage:
2022-01-11 00:46:51 +00:00
// s = format(fmt, vals);
2020-03-14 11:23:33 +00:00
// Description:
// Given a format string and a list of values, inserts the values into the placeholders in the format string and returns it.
// Formatting placeholders have the following syntax:
// - A leading `{` character to show the start of the placeholder.
// - An integer index into the `vals` list to specify which value should be formatted at that place. If not given, the first placeholder will use index `0`, the second will use index `1`, etc.
// - An optional `:` separator to indicate that what follows if a formatting specifier. If not given, no formatting info follows.
// - An optional `-` character to indicate that the value should be left justified if the value needs field width padding. If not given, right justification is used.
// - An optional `0` character to indicate that the field should be padded with `0`s. If not given, spaces will be used for padding.
// - An optional integer field width, which the value should be padded to. If not given, no padding will be performed.
// - An optional `.` followed by an integer precision length, for specifying how many digits to display in numeric formats. If not give, 6 digits is assumed.
// - An optional letter to indicate the formatting style to use. If not given, `s` is assumed, which will do it's generic best to format any data type.
// - A trailing `}` character to show the end of the placeholder.
2020-07-27 22:15:34 +00:00
// .
2020-03-14 11:23:33 +00:00
// Formatting styles, and their effects are as follows:
// - `s`: Converts the value to a string with `str()` to display. This is very generic.
// - `i` or `d`: Formats numeric values as integers.
// - `f`: Formats numeric values with the precision number of digits after the decimal point. NaN and Inf are shown as `nan` and `inf`.
// - `F`: Formats numeric values with the precision number of digits after the decimal point. NaN and Inf are shown as `NAN` and `INF`.
// - `g`: Formats numeric values with the precision number of total significant digits. NaN and Inf are shown as `nan` and `inf`. Mantissas are demarked by `e`.
// - `G`: Formats numeric values with the precision number of total significant digits. NaN and Inf are shown as `NAN` and `INF`. Mantissas are demarked by `E`.
// - `b`: If the value logically evaluates as true, it shows as `true`, otherwise `false`.
// - `B`: If the value logically evaluates as true, it shows as `TRUE`, otherwise `FALSE`.
// Arguments:
// fmt = The formatting string, with placeholders to format the values into.
// vals = The list of values to format.
// Example(NORENDER):
2022-01-11 00:46:51 +00:00
// format("The value of {} is {:.14f}.", ["pi", PI]); // Returns: "The value of pi is 3.14159265358979."
// format("The value {1:f} is known as {0}.", ["pi", PI]); // Returns: "The value 3.141593 is known as pi."
// format("We use a very small value {1:.6g} as {0}.", ["EPSILON", EPSILON]); // Returns: "We use a very small value 1e-9 as EPSILON."
// format("{:-5s}{:i}{:b}", ["foo", 12e3, 5]); // Returns: "foo 12000true"
// format("{:-10s}{:.3f}", ["plecostamus",27.43982]); // Returns: "plecostamus27.440"
// format("{:-10.9s}{:.3f}", ["plecostamus",27.43982]); // Returns: "plecostam 27.440"
function format ( fmt , vals ) =
2020-05-30 02:04:34 +00:00
let (
parts = str_split ( fmt , "{" )
) str_join ( [
for ( i = idx ( parts ) )
let (
found_brace = i = = 0 || [ for ( c = parts [ i ] ) if ( c = = "}" ) c ] ! = [ ] ,
err = assert ( found_brace , "Unbalanced { in format string." ) ,
p = i = = 0 ? [ undef , parts [ i ] ] : str_split ( parts [ i ] , "}" ) ,
fmta = p [ 0 ] ,
raw = p [ 1 ]
) each [
assert ( i < 99 )
is_undef ( fmta ) ? "" : let (
fmtb = str_split ( fmta , ":" ) ,
2022-01-11 00:46:51 +00:00
num = is_digit ( fmtb [ 0 ] ) ? parse_int ( fmtb [ 0 ] ) : ( i - 1 ) ,
2020-05-30 02:04:34 +00:00
left = fmtb [ 1 ] [ 0 ] = = "-" ,
fmtb1 = default ( fmtb [ 1 ] , "" ) ,
fmtc = left ? substr ( fmtb1 , 1 ) : fmtb1 ,
zero = fmtc [ 0 ] = = "0" ,
lch = fmtc = = "" ? "" : fmtc [ len ( fmtc ) - 1 ] ,
hastyp = is_letter ( lch ) ,
typ = hastyp ? lch : "s" ,
fmtd = hastyp ? substr ( fmtc , 0 , len ( fmtc ) - 1 ) : fmtc ,
fmte = str_split ( ( zero ? substr ( fmtd , 1 ) : fmtd ) , "." ) ,
2022-01-11 00:46:51 +00:00
wid = parse_int ( fmte [ 0 ] ) ,
prec = parse_int ( fmte [ 1 ] ) ,
2020-05-30 02:04:34 +00:00
val = assert ( num >= 0 && num < len ( vals ) ) vals [ num ] ,
unpad = typ = = "s" ? (
let ( sval = str ( val ) )
is_undef ( prec ) ? sval :
substr ( sval , 0 , min ( len ( sval ) - 1 , prec ) )
) :
2022-01-11 00:46:51 +00:00
( typ = = "d" || typ = = "i" ) ? format_int ( val ) :
2020-05-30 02:04:34 +00:00
typ = = "b" ? ( val ? "true" : "false" ) :
typ = = "B" ? ( val ? "TRUE" : "FALSE" ) :
2022-01-11 00:46:51 +00:00
typ = = "f" ? downcase ( format_fixed ( val , default ( prec , 6 ) ) ) :
typ = = "F" ? upcase ( format_fixed ( val , default ( prec , 6 ) ) ) :
typ = = "g" ? downcase ( format_float ( val , default ( prec , 6 ) ) ) :
typ = = "G" ? upcase ( format_float ( val , default ( prec , 6 ) ) ) :
2020-05-30 02:04:34 +00:00
assert ( false , str ( "Unknown format type: " , typ ) ) ,
padlen = max ( 0 , wid - len ( unpad ) ) ,
2020-10-25 22:36:30 +00:00
padfill = str_join ( [ for ( i = [ 0 : 1 : padlen - 1 ] ) zero ? "0" : " " ] ) ,
2020-05-30 02:04:34 +00:00
out = left ? str ( unpad , padfill ) : str ( padfill , unpad )
)
out , raw
]
] ) ;
2023-04-29 02:23:15 +00:00
2020-03-14 11:23:33 +00:00
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Section: Checking character class
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Function: is_lower()
2023-04-29 02:23:15 +00:00
// Synopsis: Returns true if all characters in the string are lowercase.
// Topics: Strings
// See Also: is_lower(), is_upper(), is_digit(), is_hexdigit(), is_letter()
2021-11-11 03:47:28 +00:00
// Usage:
2021-11-21 04:19:54 +00:00
// x = is_lower(s);
2021-11-11 03:47:28 +00:00
// Description:
2021-11-21 04:19:54 +00:00
// 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" ) ) ;
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Function: is_upper()
2023-04-29 02:23:15 +00:00
// Synopsis: Returns true if all characters in the string are uppercase.
// Topics: Strings
// See Also: is_lower(), is_upper(), is_digit(), is_hexdigit(), is_letter()
2021-11-11 03:47:28 +00:00
// Usage:
2021-11-21 04:19:54 +00:00
// x = is_upper(s);
2021-11-11 03:47:28 +00:00
// Description:
2021-11-21 04:19:54 +00:00
// 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" ) ) ;
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Function: is_digit()
2023-04-29 02:23:15 +00:00
// Synopsis: Returns true if all characters in the string are decimal digits.
// Topics: Strings
// See Also: is_lower(), is_upper(), is_digit(), is_hexdigit(), is_letter()
2021-11-11 03:47:28 +00:00
// Usage:
2021-11-21 04:19:54 +00:00
// x = is_digit(s);
2021-11-11 03:47:28 +00:00
// Description:
2021-11-21 04:19:54 +00:00
// 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" ) ) ;
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Function: is_hexdigit()
2023-04-29 02:23:15 +00:00
// Synopsis: Returns true if all characters in the string are hexidecimal digits.
// Topics: Strings
// See Also: is_lower(), is_upper(), is_digit(), is_hexdigit(), is_letter()
2021-11-11 03:47:28 +00:00
// Usage:
2021-11-21 04:19:54 +00:00
// x = is_hexdigit(s);
2021-11-11 03:47:28 +00:00
// Description:
2021-11-21 04:19:54 +00:00
// 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" ) ) ;
2021-11-11 03:47:28 +00:00
2021-11-21 04:19:54 +00:00
// Function: is_letter()
2023-04-29 02:23:15 +00:00
// Synopsis: Returns true if all characters in the string are letters.
// Topics: Strings
// See Also: is_lower(), is_upper(), is_digit(), is_hexdigit(), is_letter()
2021-01-01 06:30:13 +00:00
// Usage:
2021-11-21 04:19:54 +00:00
// x = is_letter(s);
2021-01-01 06:30:13 +00:00
// Description:
2021-11-21 04:19:54 +00:00
// 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 ) ] ) ;
2021-01-01 06:30:13 +00:00
2020-05-30 02:04:34 +00:00
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap