parent $libraries object $string var $root child_index 0 var $root owners [$string, $sys] var $root fertile 0 var $root inited 1 var $string alphabet "abcdefghijklmnopqrstuvwxyz" var $string numbers "1234567890" var $string non_alphanumeric "!@#$%^&*()_+-=~`'{}[]|/?\"\\,.<>;: " var $root owned [$string] var $root manager $string var $root writable [$string] var $root readable ['parameters, 'methods, 'code] var $root dbref 'string method left arg str, width, [fchar]; // will NOT chop off 'str' if it is longer than width, use pad() for that. if (fchar) return str + ((strlen(str) < width) ? pad("", width - strlen(str), fchar[1]) | ""); else return str + ((strlen(str) < width) ? pad("", width - strlen(str)) | ""); . method fill arg n, [args]; var fill, x; // same as pad("", n, [args]); fill = [@args, " "][1]; return pad("", n, fill); . method center arg text, len, [args]; var lfill, rfill, textlen, padlen; // args[1] == string to center // args[2] == integer of width to center in // args[3] <op> == what to fill the left|right side with. // args[4] <op> == what to fill the right side with. lfill = ((listlen(args) >= 1) && (args[1])) || " "; rfill = (listlen(args) >= 2) ? args[2] | ((lfill == " ") ? "" | lfill); textlen = strlen(text); padlen = (len - textlen) / 2; if (textlen < len) return ((.fill(padlen, lfill)) + text) + (rfill ? .fill(padlen, rfill) | ""); else return (len > 0) ? text | pad(text, len); . method trim arg string, [args]; var rl, chars, type; // remove leading and trailing characters. // if args includes a string, it takes that as the strip string. // args can also include symbols of what edge to trim: 'left 'right (or both) // left and right defaults on. rl = []; while (args) { type = type(args[1]); if (type == 'string) chars = args[1]; else if (type == 'symbol) rl = [@rl, args[1]]; args = sublist(args, 2); } if (!chars) chars = " "; if (!rl) rl = ['left, 'right]; if ('left in rl) { // strip from left while (string && ((string[1]) in chars)) string = substr(string, 2); } if ('right in rl) { // strip from right while (string && ((string[strlen(string)]) in chars)) string = substr(string, 1, strlen(string) - 1); } return string; . method to_list arg str, [sep]; var result, list; // separate a string into a list of strings, breaking wherever 'sep' appears. // if not provided, sep defaults to a comma. // One word of warning. sep should not contain an asterisk. If it does, // this routine will separate the string oddly, most likely losing bits. if (!str) return []; sep = ("*" + (sep ? sep[1] | ",")) + "*"; list = []; while (1) { result = match_pattern(sep, str); if (result) { list = list + [result[1]]; str = result[2]; } else { return list + [str]; } } . method right arg str, width, [fchar]; // will not chop off 'str' if it is longer than width (unlike pad()) if (fchar) return pad("", width - strlen(str), fill_char[1]) + str; else return pad("", width - strlen(str)) + str; . method alphabet return alphabet; . method numbers return numbers; . method capitalize arg string; // Capitalizes the first character of a word. return uppercase(string[1]) + substr(string, 2); . method is_numeric arg string; return toint(string) || (string == "0"); . method a_or_an arg string; if (lowercase(string[1]) in "aeiou") return "an"; return "a"; . method strip arg string, strip; var new_str, char; // strips all of "strip" characters from the string // if "strip" is -1 it will use .non_alphanumeric() if ((type(string) != 'string) || ((type(strip) != 'string) && (strip != (-1)))) throw(~type, "First argument must be a string, second can be -1"); new_str = ""; if (strip == (-1)) new_str = non_alphanumeric; for char in [1 .. strlen(string)] { if (!((string[char]) in strip)) new_str = new_str + (string[char]); } return new_str; . method non_alphanumeric return non_alphanumeric; . method chop arg str, len, [end]; // chops string off strlen(end) characters before len and appends len end = [@end, "..."][1]; if (strlen(str) < len) return str; if (strlen(str) < strlen(end)) return str; return pad(str, len - strlen(end)) + end; . method replace arg string, replace, [char]; var new_str, character; // replaces 'replace' with the character in 'char' // if 'replace' is -1 will use .non_alphanumeric(); if ((type(string) != 'string) || ((type(replace) != 'string) && (strip != (-1)))) throw(~type, "First argument must be a string, second can be -1"); char = [@char, " "][1]; new_str = ""; if (replace == (-1)) new_str = non_alphanumeric; for character in [1 .. strlen(string)] { if (!((string[character]) in replace)) new_str = new_str + (string[character]); else new_str = new_str + char; } return new_str; . method explode_english_list arg line, [opts]; var x, output, tmp; // explodes an english list ("foo, bar and zoo"). line = explode(line, ","); output = []; for x in (line) { x = .trim(x); if ((| substr(x, 1, 3) |) == "and") output = [@output, .trim(substr(x, 4))]; else output = [@output, x]; } // check the last element, if they didn't specify 'noand if (!('noand in opts)) { line = explode(output[listlen(output)]); tmp = ""; for x in [1 .. listlen(line)] { if ((line[x]) == "and") { output = delete(output, listlen(output)); if (tmp) output = [@output, tmp]; tmp = $list.to_string(sublist(line, x + 1)); if (tmp) output = [@output, tmp]; // only bother with the first "and" break; } tmp = (tmp + (tmp ? " " | "")) + (line[x]); } } return output; . method explode_delimited arg str, left, right; var pattern, parsed, matched, match_num, match_result; // parse str looking for anything surrounded by left and right // ;$string.explode_delimited("foo%[bar]baz", "%[", "]") // => [["foo", 1, "baz"], ["bar"]] pattern = ((("*" + left) + "*") + right) + "*"; parsed = []; matched = []; match_num = 0; while (str) { match_result = match_pattern(pattern, str); if (match_result) { match_num = match_num + 1; parsed = [@parsed, match_result[1], match_num]; matched = [@matched, match_result[2]]; str = match_result[3]; } else { parsed = [@parsed, str]; str = ""; } } return [parsed, matched]; . method wrap_line arg string, length, [stuff]; var output, cutoff, firstline, prefix; // takes string and wraps it by words, compared to length, returns a list. prefix = [@stuff, ""][1]; firstline = [@stuff, 0, 0][2]; output = []; length = length - strlen(prefix); if (firstline) string = prefix + string; while (strlen(string) > length) { cutoff = .rindex(substr(string, 1, length), " "); output = [@output, substr(string, 1, cutoff - 1)]; string = prefix + substr(string, cutoff + 1); } return [@output, string]; . method rindex arg string, index; var loc, rest; // returns the first occurance of index starting from the end of the string, // and moving to the beginning. loc = index in string; rest = loc && substr(string, loc + 1); while (loc && (index in rest)) { loc = loc + (index in rest); rest = loc && substr(string, loc + 1); } return loc; . method match_sub_tag arg string, tag; var x, expl, output, match, matches; // matches a string between 'tag' and " " in a larger string against // the sender's environment. If a match is found it subs the match.name // with the string, otherwize it lets it pass through with the tag, ie: // .match_sub_tag("this test #of something #note or other"); // => "this test #of something Note of sorts or other" // where the note is in the sender's environment. expl = .explode_delimited(string + " ", tag, " "); matches = expl[2]; expl = expl[1]; output = ""; for x in (expl) { if (type(x) == 'integer) { match = (| sender().match_environment(matches[x]) |); if (match) output = (output + (match.namef())) + " "; else output = ((output + tag) + (matches[x])) + " "; } else { output = output + x; } } return substr(output, 1, strlen(output) - 1); . method search_pat arg pat, text, [start_at]; var line, match_result, type; line = 1; type = (([@start_at, 'pattern, 'pattern][2]) == 'pattern) ? 'match_pattern | 'match_regexp; if (start_at) { line = start_at[1]; start_at = [@start_at, 1, 1][2]; match_result = pat.(type)(substr(text[line], line)); if (match_result != 0) { if (type == 'match_pattern) { pat = $string.pat_sub(pat, match_result); return [line, (start_at + pat) in substr(text[line], start_at)]; } else { return [line, start_at + ((match_result[1])[1])]; } } line = line + 1; } while (line <= listlen(text)) { match_result = pat.(type)(text[line]); if (match_result != 0) { if (type == 'pattern) { pat = $string.pat_sub(pat, match_result); return [line, pat in (text[line])]; } else { return [line, (match_result[1])[1]]; } } line = line + 1; } throw(~strnf, "String not found in text."); . method pat_sub arg pat, subs; var wc_idx; // wc_idx == wildcard index while (subs) { wc_idx = "*" in pat; if (wc_idx == 1) pat = (subs[1]) + substr(pat, 2); else if (wc_idx == strlen(pat)) pat = substr(pat, 1, wc_idx - 1) + (subs[1]); else pat = (substr(pat, 1, wc_idx - 1) + (subs[1])) + substr(pat, wc_idx + 1); subs = delete(subs, 1); } return pat; . method is_boolean arg str; if (match_begin("yes", str) || (match_begin("true", str) || (str == "1"))) return 1; else if (match_begin("no", str) || (match_begin("false", str) || (str == "0"))) return 0; else return -1; . method parse_template arg str; var index, out; out = explode(str, " *")[1]; // index = "?" in str; // if (index) { // out = uppercase(substr(str, 1, index - 1)); // out = out + "?" + substr(str, index + 1); // } else { // out = uppercase(out); // } return out; . method repeat arg string, times; var t, out; // repeats <string> <times> times if (type(string) != 'string) throw(~type, "The first agrument must be a string."); if ((type(times) != 'integer) || (times < 0)) throw(~type, "The second agrument must be a non-negatiive integer."); out = ""; for t in [1 .. times] out = out + string; return out; . method explode arg [args]; return (> explode(@args) <); . method match_template arg [args]; return (> match_template(@args) <); . method find_next arg str, choices; var t, first, pos; //Returns the index of the first string in choices to appear. //Returns strlen(str) if none are in str. first = strlen(str) + 1; for t in (choices) { pos = t in str; if (pos && (pos < first)) first = pos; } return first; . method split_on_next arg str, choices; var pos, pre, post; // splits str around whichever choice appears first. pos = $string.find_next(str, choices); pre = (| substr(str, 1, pos - 1) |) || ""; post = (| substr(str, pos + 1) |) || ""; return [pre, (| str[pos] |) || "", post]; . method explode_template_word arg template; var t, x, idx, out, new; // this only explodes single word templates template = explode(template, "|"); out = []; for t in (template) { idx = "?" in t; if (idx) { t = t.strip("?"); new = substr(t, 1, idx - 1); out = [@out, new]; for x in [idx .. strlen(t)] { new = new + (t[x]); out = [@out, new]; } } else { out = [@out, t]; } } return out; . method match_pattern arg [args]; return (> match_pattern(@args) <); . method match_regexp arg [args]; return (> match_regexp(@args) <); . method to_number arg str; if (str.is_numeric()) return toint(str); throw(~type, ("\"" + str) + "\" is not a number."); .