Category talk:Wren-fmt: Difference between revisions
Content added Content deleted
(→Source code: tprint and cprint can now use separators other than a single space. Fixed some other minor issues.) |
(→Source code: Added 'numbers to names' routines, plus several other minor improvements.) |
||
Line 112: | Line 112: | ||
if (!(n is Num && n.isInteger)) Fiber.abort("Argument must be an integer.") |
if (!(n is Num && n.isInteger)) Fiber.abort("Argument must be an integer.") |
||
var ss = { |
var ss = { |
||
"0": "⁰", "1": "¹", "2": "²", "3": "³", "4": "⁴", "5": "⁵", |
"0": "⁰", "1": "¹", "2": "²", "3": "³", "4": "⁴", "5": "⁵", "6": "⁶", |
||
"7": "⁷", "8": "⁸", "9": "⁹", "-": "⁻", "+": "⁺", "e": "ᵉ" |
|||
} |
} |
||
return n.toString.map { |d| ss[d] }.join() |
//return n.toString.map { |d| ss.containsKey(d) ? ss[d] : d }.join() |
||
return Fmt.i(0, n).map { |d| ss.containsKey(d) ? ss[d] : d }.join() |
|||
} |
} |
||
Line 122: | Line 123: | ||
if (!(n is Num && n.isInteger)) Fiber.abort("Argument must be an integer.") |
if (!(n is Num && n.isInteger)) Fiber.abort("Argument must be an integer.") |
||
var ss = { |
var ss = { |
||
"0": "₀", "1": "₁", "2": "₂", "3": "₃", "4": "₄", "5": "₅", |
"0": "₀", "1": "₁", "2": "₂", "3": "₃", "4": "₄", "5": "₅", "6": "₆", |
||
"7": "₇", "8": "₈", "9": "₉", "-": "₋", "+": "₊", "e": "ₑ" |
|||
} |
} |
||
return n |
return Fmt.i(0, n).map { |d| ss.containsKey(d) ? ss[d] : d }.join() |
||
} |
} |
||
Line 395: | Line 396: | ||
// Works like 'e' except that the exponent symbol 'e' is replaced by upper case 'E'. |
// Works like 'e' except that the exponent symbol 'e' is replaced by upper case 'E'. |
||
static E(w, n, p) { e(w, n, p).replace("e", "E") } |
static E(w, n, p) { e(w, n, p).replace("e", "E") } |
||
// Applies the 's' format to the name of a number 'n'. |
|||
static N(w, n) { Fmt.s(w, Name.fromNum(n)) } |
|||
// Applies the 's' format to the ordinal name of an integer 'i'. |
|||
static O(w, i) { Fmt.s(w, Name.ordinal(i)) } |
|||
// Applies the 's' format to the superior (or superscript) version of a number 'n'. |
|||
static S(w, n) { Fmt.s(w, Conv.superscript(n)) } |
|||
// Applies the 's' format to the the inferior (or subscript) version of a number 'n'. |
|||
static I(w, n) { Fmt.s(w, Conv.subscript(n)) } |
|||
// Pads a number 'n' with leading spaces to a minimum width 'w' and a precision of 'p' decimal places. |
// Pads a number 'n' with leading spaces to a minimum width 'w' and a precision of 'p' decimal places. |
||
Line 583: | Line 596: | ||
(fn == "e") ? e(w, v, p) : |
(fn == "e") ? e(w, v, p) : |
||
(fn == "E") ? Fmt.E(w, v, p) : |
(fn == "E") ? Fmt.E(w, v, p) : |
||
(fn == "N") ? Fmt.N(w, v) : |
|||
(fn == "O") ? Fmt.O(w, v) : |
|||
(fn == "S") ? Fmt.S(w, v) : |
|||
(fn == "I") ? Fmt.I(w, v) : |
|||
(fn == "f") ? f(w, v, p) : |
(fn == "f") ? f(w, v, p) : |
||
(fn == "g") ? g(w, v, p) : |
(fn == "g") ? g(w, v, p) : |
||
Line 696: | Line 713: | ||
// $[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, k, m, n, o, q, r, s, t, u, x, X or z. |
// 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. |
||
// 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) |
||
Line 766: | Line 783: | ||
var fn = "" |
var fn = "" |
||
var ds = "" |
var ds = "" |
||
if (" |
if ("abcdeEfghiIkmnNoOqrsStuxXz".codePoints.contains(cp)) { // format letter |
||
fn = Conv.itoc(cp) |
fn = Conv.itoc(cp) |
||
} else if (cp == 42) { // star |
} else if (cp == 42) { // star |
||
Line 801: | Line 818: | ||
if (fn == "") { |
if (fn == "") { |
||
if (!" |
if (!"abcdeEfghiIkmnNoOqrsStuxXz".codePoints.contains(cp)) { |
||
Fiber.abort("Unrecognized character in format string.") |
Fiber.abort("Unrecognized character in format string.") |
||
} |
} |
||
Line 1,040: | Line 1,057: | ||
System.print(spwrite(fmt, coefs, symbol, variable)) |
System.print(spwrite(fmt, coefs, symbol, variable)) |
||
} |
} |
||
} |
|||
}</syntaxhighlight> |
|||
/* Name contains infrastructure and routines for converting numbers to their English names. */ |
|||
class Name { |
|||
// Private method to initialize static fields. |
|||
static init_() { |
|||
__uk = false |
|||
__neg = "minus" |
|||
__point = "point" |
|||
__zero = "zero" |
|||
__small = [ |
|||
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", |
|||
"twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" |
|||
] |
|||
__tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"] |
|||
__illions = [ |
|||
"", " thousand", " million", " billion"," trillion", " quadrillion", " quintillion", |
|||
" sextillion", " septillion", " octillion", " nonillion", " decillion" |
|||
] |
|||
__irregularOrdinals = { |
|||
"nought": "noughth", |
|||
"one": "first", |
|||
"two": "second", |
|||
"three": "third", |
|||
"five": "fifth", |
|||
"eight": "eighth", |
|||
"nine": "ninth", |
|||
"twelve": "twelfth" |
|||
} |
|||
} |
|||
// Gets or sets precision for 'f(w, n)' style convenience methods. |
|||
static precision { ( __precision != null) ? __precision : 6 } |
|||
static precision=(p) { __precision = ((p is Num) && p.isInteger && p >= 0) ? p : __precision } |
|||
// Gets or sets whether names are to expressed in UK English i.e. 'and' is used to connect |
|||
// double or single digit numbers with larger numbers. The default is 'false'. |
|||
static uk { __uk } |
|||
static uk=(b) { __uk = (b is Bool) ? b : __uk} |
|||
// Gets or sets the prefix word for negative numbers. The default is "minus" though another |
|||
// possibility is "negative". |
|||
static negative { __neg } |
|||
static negative=(n) { __neg = (n is String) ? n : __neg } |
|||
// Gets or sets the word for the decimal point in non-integral numbers. The default is "point" |
|||
// though other possibilities are "dot" or "spot". |
|||
static point { __point } |
|||
static point=(p) { __point = (p is String) ? p : __point } |
|||
// Gets or sets the word for the number '0'. The default is "zero" though another |
|||
// possibility is 'nought'. |
|||
static zero { __zero } |
|||
static zero=(z) { __zero = (z is String) ? __small[0] = z : __zero } |
|||
// Returns the name of a number which can be positive or negative and can include a decimal point. |
|||
// Note that this is unsafe for numbers with an absolute value >= 2^53 but may work in some cases. |
|||
static fromNum(n) { |
|||
if (!(n is Num)) Fiber.abort("'n' must be a number.") |
|||
if (n.isInfinity || n.isNan) return Fmt.s(0, n) |
|||
var f = 0 |
|||
if (!n.isInteger) { |
|||
f = n.fraction |
|||
n = n.truncate |
|||
} |
|||
var and = __uk ? "and " : "" |
|||
var t = "" |
|||
if (n < 0) { |
|||
t = __neg + " " |
|||
n = -n |
|||
} |
|||
if (n < 20) { |
|||
t = t + __small[n] |
|||
} else if (n < 100) { |
|||
t = t + __tens[(n/10).floor] |
|||
var s = n % 10 |
|||
if (s > 0) t = t + "-" + __small[s] |
|||
} else if (n < 1000) { |
|||
t = t + __small[(n/100).floor] + " hundred" |
|||
var s = n % 100 |
|||
if (s > 0) t = t + " " + and + fromNum(s) |
|||
} else { |
|||
var sx = "" |
|||
var i = 0 |
|||
while (n > 0) { |
|||
var p = n % 1000 |
|||
n = (n/1000).floor |
|||
if (p > 0) { |
|||
var ix = fromNum(p) + __illions[i] |
|||
if (sx != "") ix = ix + " " + sx |
|||
sx = ix |
|||
} |
|||
i = i + 1 |
|||
} |
|||
t = t + sx |
|||
} |
|||
if (f > 0) { |
|||
t = t + " " + __point |
|||
for (d in f.toString.skip(2)) { |
|||
t = t + " %(__small[Num.fromString(d)])" |
|||
} |
|||
} |
|||
return t |
|||
} |
|||
// Returns the ordinal name of an integer (including negative integers). |
|||
// Note that this is unsafe for integers with an absolute value >= 2^53 but may work in some cases. |
|||
static ordinal(n) { |
|||
if (!(n is Num && n.isInteger)) Fiber.abort("'n' must be an integer.") |
|||
var s = fromNum(n) |
|||
var r = s[-1..0] |
|||
var i1 = r.indexOf(" ") |
|||
if (i1 != -1) i1 = s.count - 1 - i1 |
|||
var i2 = r.indexOf("-") |
|||
if (i2 != -1) i2 = s.count - 1 - i2 |
|||
var i = (i1 > i2) ? i1 : i2 |
|||
i = i + 1 |
|||
var x = __irregularOrdinals[s[i..-1]] |
|||
if (x) { |
|||
return s[0...i] + x |
|||
} else if (s[-1] == "y") { |
|||
return s[0...i] + s[i..-2] + "ieth" |
|||
} else { |
|||
return s[0...i] + s[i..-1] + "th" |
|||
} |
|||
} |
|||
} |
|||
Name.init_()</syntaxhighlight> |