Category talk:Wren-fmt: Difference between revisions
Content added Content deleted
(→Source code: Added 'numbers to names' routines, plus several other minor improvements.) |
(→Source code: Added Name.toNum method and two more floating point formats.) |
||
Line 466: | Line 466: | ||
return f |
return f |
||
} |
} |
||
// Works like 'h' except, if right justified, removes any trailing spaces before rejustifying. |
|||
static j(w, n, p) { (w >= 0) ? rjust(w, h(w, n, p).trimEnd()) : h(w, n, p) } |
|||
// Works like 'j' except derives the number to be formatted from its name. |
|||
static l(w, name, p) { j(w, Name.toNum(name), p) } |
|||
// As above but pads with leading zeros instead of spaces. |
// As above but pads with leading zeros instead of spaces. |
||
Line 530: | Line 536: | ||
return f |
return f |
||
} |
} |
||
// Works like 'hc' except, if right justified, removes any trailing spaces before rejustifying. |
|||
static jc(w, n, p) { (w >= 0) ? rjust(w, hc(w, n, p).trimEnd()) : hc(w, n, p) } |
|||
// Works like 'jc' except derives the number to be formatted from its name. |
|||
static lc(w, name, p) { jc(w, Name.toNum(name), p) } |
|||
// Applies the 'f' format to each component, x and y, of a complex number 'n' |
// Applies the 'f' format to each component, x and y, of a complex number 'n' |
||
Line 561: | Line 573: | ||
static g(w, n) { g(w, n, precision) } |
static g(w, n) { g(w, n, precision) } |
||
static h(w, n) { h(w, n, precision) } |
static h(w, n) { h(w, n, precision) } |
||
static j(w, n) { j(w, n, precision) } |
|||
static l(w, n) { l(w, n, precision) } |
|||
static z(w, n) { z(w, n, precision) } |
static z(w, n) { z(w, n, precision) } |
||
static fz(w, n) { fz(w, n, precision) } |
static fz(w, n) { fz(w, n, precision) } |
||
Line 574: | Line 588: | ||
static fc(w, n) { fc(w, n, precision) } |
static fc(w, n) { fc(w, n, precision) } |
||
static gc(w, n) { gc(w, n, precision) } |
static gc(w, n) { gc(w, n, precision) } |
||
static hc(w, n) { hc(w, n, precision) } |
static hc(w, n) { hc(w, n, precision) } |
||
static jc(w, n) { jc(w, n, precision) } |
|||
static lc(w, n) { lc(w, n, precision) } |
|||
// Private worker method which calls a 'short name' method and returns its result. |
// Private worker method which calls a 'short name' method and returns its result. |
||
static callFn_(fn, w, v, p) { |
static callFn_(fn, w, v, p) { |
||
Line 603: | Line 619: | ||
(fn == "g") ? g(w, v, p) : |
(fn == "g") ? g(w, v, p) : |
||
(fn == "h") ? h(w, v, p) : |
(fn == "h") ? h(w, v, p) : |
||
(fn == "j") ? j(w, v, p) : |
|||
(fn == "l") ? l(w, v, p) : |
|||
(fn == "z") ? z(w, v, p) : |
(fn == "z") ? z(w, v, p) : |
||
(fn == "dz") ? dz(w, v) : |
(fn == "dz") ? dz(w, v) : |
||
Line 630: | Line 648: | ||
(fn == "fc") ? fc(w, v, p) : |
(fn == "fc") ? fc(w, v, p) : |
||
(fn == "gc") ? gc(w, v, p) : |
(fn == "gc") ? gc(w, v, p) : |
||
(fn == "hc") ? hc(w, v, p) : |
(fn == "hc") ? hc(w, v, p) : |
||
(fn == "jc") ? jc(w, v, p) : |
|||
(fn == "lc") ? lc(w, v, p) : Fiber.abort("Method not recognized.") |
|||
} |
} |
||
Line 636: | Line 656: | ||
// The method to be applied is specified (as a string) in 'fn'. |
// The method to be applied is specified (as a string) in 'fn'. |
||
// The parameters to be passed to the method are specified in 'w' and 'p' |
// The parameters to be passed to the method are specified in 'w' and 'p' |
||
// 'p' is needed for 'e', 'E', 'f', 'g', 'h', 'z', 'fz', 'gz', 'hz', 'fp', 'gp', |
// 'p' is needed for 'e', 'E', 'f', 'g', 'h', 'j', 'l', 'z', 'fz', 'gz', 'hz', 'fp', 'gp', |
||
// 'fm', 'gm', 'hm', 'zm', 'fc', 'gc' or ' |
// 'hp', 'fm', 'gm', 'hm', 'zm', 'fc', 'gc', 'hc', 'jc' or 'lc' but is ignored otherwise. |
||
// The resulting strings are then joined together using the separator 'sep'. |
// The resulting strings are then joined together using the separator 'sep'. |
||
// having first applied the 'q' method, with parameter 'cc', to each of them. |
// having first applied the 'q' method, with parameter 'cc', to each of them. |
||
Line 713: | Line 733: | ||
// $[flag][width][.precision][letter] of which all bracketed items except [letter] are optional. |
// $[flag][width][.precision][letter] of which all bracketed items except [letter] are optional. |
||
// The letter must be one of the 'short' methods: |
// The letter must be one of the 'short' methods: |
||
// a, b, c, d, e, E, f, g, h, i, I, k, m, n, N, o, O, q, r, s, S, t, u, x, X or z. |
// a, b, c, d, e, E, f, g, h, i, I, j, k, l, m, n, N, o, O, q, r, s, S, t, u, x, X or z. |
||
// If present, the flag (there can only be one) must be one of the following: |
// If present, the flag (there can only be one) must be one of the following: |
||
// + always prints a + or - sign ('dp', 'fp', 'gp' or 'hp' methods) |
// + always prints a + or - sign ('dp', 'fp', 'gp' or 'hp' methods) |
||
// (space) leaves a space for the sign but only prints minus ('dm', 'fm', 'gm', 'hm' or 'zm' methods) |
// (space) leaves a space for the sign but only prints minus ('dm', 'fm', 'gm', 'hm' or 'zm' methods) |
||
// , commatizes the following number ('dc', 'rc', 'sc', 'ic', 'fc', 'gc' or ' |
// , commatizes the following number ('dc', 'rc', 'sc', 'ic', 'fc', 'gc, 'hc', 'jc' or 'lc' methods) |
||
// # adds the appropriate prefix for the number formats: b, t, o, d, x and X |
// # adds the appropriate prefix for the number formats: b, t, o, d, x and X |
||
// * reads the width from the argument before the one to be formatted |
// * reads the width from the argument before the one to be formatted |
||
Line 725: | Line 745: | ||
// It doesn't include any '#' flag prefix. If [width] is absent, a width of one is passed. |
// It doesn't include any '#' flag prefix. If [width] is absent, a width of one is passed. |
||
// If present, the precision is the number of decimal places to be passed to the appropriate |
// If present, the precision is the number of decimal places to be passed to the appropriate |
||
// 'e', 'E', 'f', 'g', 'h' or 'z' style method. If absent, the default precision is passed. |
// 'e', 'E', 'f', 'g', 'h', 'j', 'l' or 'z' style method. If absent, the default precision is passed. |
||
// Where any optional item is inappropriate to the method being used it is simply ignored. |
// Where any optional item is inappropriate to the method being used it is simply ignored. |
||
// Where one of the arguments is a sequence (other than a string) this method senses it |
// Where one of the arguments is a sequence (other than a string) this method senses it |
||
Line 783: | Line 803: | ||
var fn = "" |
var fn = "" |
||
var ds = "" |
var ds = "" |
||
if (" |
if ("abcdeEfghiIjklmnNoOqrsStuxXz".codePoints.contains(cp)) { // format letter |
||
fn = Conv.itoc(cp) |
fn = Conv.itoc(cp) |
||
} else if (cp == 42) { // star |
} else if (cp == 42) { // star |
||
Line 818: | Line 838: | ||
if (fn == "") { |
if (fn == "") { |
||
if (!" |
if (!"abcdeEfghiIjklmnNoOqrsStuxXz".codePoints.contains(cp)) { |
||
Fiber.abort("Unrecognized character in format string.") |
Fiber.abort("Unrecognized character in format string.") |
||
} |
} |
||
Line 836: | Line 856: | ||
fn = fn + "m" |
fn = fn + "m" |
||
} else if ((fn == "r" || fn == "s" || fn == "i" || fn == "f" || |
} else if ((fn == "r" || fn == "s" || fn == "i" || fn == "f" || |
||
fn == "g" || fn == "h") && comma) { |
fn == "g" || fn == "h" || fn == "j" || fn == "l") && comma) { |
||
fn = fn + "c" |
fn = fn + "c" |
||
} |
} |
||
Line 1,039: | Line 1,059: | ||
p = p + Fmt.swrite("$s$s$d", variable, symbol, pow) |
p = p + Fmt.swrite("$s$s$d", variable, symbol, pow) |
||
} else { |
} else { |
||
p = p + Fmt.swrite("$s$ |
p = p + Fmt.swrite("$s$S", variable, pow) |
||
} |
} |
||
} else if (pow == 1) { |
} else if (pow == 1) { |
||
Line 1,090: | Line 1,110: | ||
"twelve": "twelfth" |
"twelve": "twelfth" |
||
} |
} |
||
__revIrregulars = {} |
|||
for (me in __irregularOrdinals) __revIrregulars[me.value] = me.key |
|||
__names = {} |
|||
for (i in 0..19) __names[__small[i]] = i |
|||
for (i in 2..9) __names[__tens[i]] = i * 10 |
|||
__names["hundred"] = 100 |
|||
for (i in 1..11) __names[__illions[i][1..-1]] = 10.pow(i * 3) |
|||
__names["nought"] = 0 |
|||
__zeros = ["zero", "nought", "nil", "none", "nothing"] |
|||
__points = ["point", "dot", "spot"] |
|||
} |
} |
||
// Private helper function. Converts ASCII string to lower case. |
|||
// Gets or sets precision for 'f(w, n)' style convenience methods. |
|||
static |
static lower_(s) { s.bytes.map { |b| |
||
return String.fromByte((b >= 65 && b <= 90) ? b + 32 : b) |
|||
}.join() } |
|||
// Gets or sets whether names are to expressed in UK English i.e. 'and' is used to connect |
// Gets or sets whether names are to expressed in UK English i.e. 'and' is used to connect |
||
Line 1,186: | Line 1,221: | ||
return s[0...i] + s[i..-1] + "th" |
return s[0...i] + s[i..-1] + "th" |
||
} |
} |
||
} |
|||
// Translates the name of a number or ordinal integer into that number and returns it. |
|||
// Ignores case and custom settings but recognizes all suggested alternatives and some others. |
|||
static toNum(name) { |
|||
if (!(name is String) || name == "") Fiber.abort("'name' must be a non-empty string.") |
|||
name = lower_(name).replace(",", " ").replace("-", " ").replace(" and", "") |
|||
var words = name.split(" ").where { |w| w != "" }.toList |
|||
var isNegative = words[0] == "minus" || words[0] == "negative" |
|||
if (isNegative || words[0] == "plus") words = words[1..-1] |
|||
if (words[0] == "a") words[0] = "one" |
|||
if (words[-1].endsWith("ieth")) { |
|||
words[-1] = words[-1][0..-5] + "y" |
|||
} else if(__revIrregulars.containsKey(words[-1])) { |
|||
words[-1] = __revIrregulars[words[-1]] |
|||
} else if (words[-1].endsWith("th")) { |
|||
words[-1] = words[-1][0..-3] |
|||
} |
|||
var size = words.count |
|||
if (size == 1 && __zeros.contains(words[0])) return 0 |
|||
if (size == 1 && words[0] == "nan") return Num.nan |
|||
if (size == 1 && words[0] == "infinity") return isNegative ? -Num.infinity : Num.infinity |
|||
var ix = -1 |
|||
for (p in __points) { |
|||
if ((ix = words.indexOf(p)) >= 0) break |
|||
} |
|||
if (ix == 0) { |
|||
words.insert(0, "zero") |
|||
ix = 1 |
|||
} |
|||
var dec = "" |
|||
if (ix > 0) { |
|||
for (word in words[ix+1..-1]) dec = dec + __names[word].toString |
|||
size = ix |
|||
} |
|||
var multiplier = 1 |
|||
var lastNum = -1 |
|||
var sum = 0 |
|||
for (i in size-1..0) { |
|||
var num = __names[words[i]] |
|||
if (!num) Fiber.abort("'%(words[i])' is not a valid cardinal number.") |
|||
if (num == lastNum) Fiber.abort("'%(name)' is not a well formed numeric string.") |
|||
if (num >= 1000) { |
|||
if (lastNum >= 100) { |
|||
Fiber.abort("'%(name)' is not a well formed numeric string.") |
|||
} |
|||
multiplier = num |
|||
if (i == 0) sum = sum + multiplier |
|||
} else if (num >= 100) { |
|||
multiplier = multiplier * 100 |
|||
if (i == 0) sum = sum + multiplier |
|||
} else if (num >= 20) { |
|||
if (lastNum >= 10 && lastNum <= 90) { |
|||
Fiber.abort("'%(name)' is not a well formed numeric string.") |
|||
} |
|||
sum = sum + num*multiplier |
|||
} else { |
|||
if (lastNum >= 1 && lastNum <= 90) { |
|||
Fiber.abort("'%(name)' is not a well formed numeric string.") |
|||
} |
|||
sum = sum + num*multiplier |
|||
} |
|||
lastNum = num |
|||
} |
|||
if (dec != "") sum = sum + Num.fromString("0." + dec) |
|||
return (isNegative) ? -sum : sum |
|||
} |
} |
||
} |
} |