Category talk:Fmt: Difference between revisions

→‎Source code: Fixed some bugs, lots of improvements. Hopefully fairly stable now.
(→‎Source code: Found and fixed a minor bug.)
(→‎Source code: Fixed some bugs, lots of improvements. Hopefully fairly stable now.)
Line 3:
<lang ecmascript>/* Module "fmt.wren" */
 
/* Str contains routines which applymanipulate commonstrings transformationsin tovarious stringsways. */
class Str {
// Converts a string or list of strings to lower case.
static lower(s) {
if (!(s is String)) s = "%(s)"
Line 17:
}
 
// Converts a string or list of strings to upper case.
static upper(s) {
if (!(s is String)) s = "%(s)"
Line 29:
}
 
// CapitalizesSwaps the firstcase of each character ofin a string or list of strings.
static swapCase(s) {
if (!(s is String)) s = "%(s)"
if (s == "") return s
var cps = s.codePoints.toList
for (i in 0...cps.count) {
var c = cps[i]
if (c >= 65 && c <= 90) {
cps[i] = c + 32
} else if (c >= 97 && c <= 122) {
cps[i] = c - 32
}
}
return cps.reduce("") { |acc, c| acc + String.fromCodePoint(c) }
}
 
// Capitalizes the first character of a string.
static capitalize(s) {
if (!(s is String)) s = "%(s)"
Line 43 ⟶ 59:
}
 
// Capitalizes the first character of each word of a string or list of strings.
static title(s) {
if (!(s is String)) s = "%(s)"
Line 51 ⟶ 67:
}
 
// Reverses the code pointscharacters (not necessarily single bytes) of a string.
static reverse(s) {
if (!(s is String)) s = "%(s)"
ifreturn (s =!= "") return? s[-1..0] : s
}
return s.codePoints.toList[-1..0].reduce("") { |acc, c| acc + String.fromCodePoint(c) }
 
// Performs a circular shift of the characters of 's' one place to the left.
static lshift(s) {
if (!(s is String)) s = "%(s)"
var chars = s.toList
var count = chars.count
if (count < 2) return s
var t = chars[0]
for (i in 0..count-2) chars[i] = chars[i+1]
chars[-1] = t
return chars.join()
}
 
// Performs a circular shift of the characters of 's' one place to the right.
static rshift(s) {
if (!(s is String)) s = "%(s)"
var chars = s.toList
var count = chars.count
if (count < 2) return s
var t = chars[-1]
for (i in count-2..0) chars[i+1] = chars[i]
chars[0] = t
return chars.join()
}
 
/* The indices (or ranges thereof) for all the following functions are measured in codepoints (not bytes).
As with core library methods, the indices must be within bounds or errors will be generated. */
 
// Extracts the sub-string of 's' over the range 'r'.
static sub(s, r) {
if (!(r is Range)) Fiber.abort("Second argument must be a range.")
if (!(s is String)) s = "%(s)"
return s.toList[r].join()
}
 
// Gets the character of 's' at index 'i'.
static get(s, i) {
if (!(i is Num && i.isInteger && i >= 0)) Fiber.abort("Index must be a non-negative integer.")
if (!(s is String)) s = "%(s)"
return s.toList[i]
}
 
// Changes the character of 's' at index 'i' to the string 't'.
static change(s, i, t) {
if (!(i is Num && i.isInteger && i >= 0)) Fiber.abort("Index must be a non-negative integer.")
if (!(t is String)) Fiber.abort("Replacment must be a string.")
if (!(s is String)) s = "%(s)"
var chars = s.toList
chars[i] = t
return chars.join()
}
 
// Inserts at index 'i' of 's' the string 't'.
static insert(s, i, t) {
if (!(i is Num && i.isInteger && i >= 0)) Fiber.abort("Index must be a non-negative integer.")
if (!(t is String)) Fiber.abort("Insertion must be a string.")
if (!(s is String)) s = "%(s)"
var chars = s.toList
chars.insert(i, t)
return chars.join()
}
 
// Deletes the character of 's' at index 'i'.
static delete(s, i) {
if (!(i is Num && i.isInteger && i >= 0)) Fiber.abort("Index must be a non-negative integer.")
if (!(s is String)) s = "%(s)"
var chars = s.toList
chars.removeAt(i)
return chars.join()
}
 
// Exchanges the characters of 's' at indices 'i' and 'j'
static exchange(s, i, j) {
if (!(i is Num && i.isInteger && i >= 0)) Fiber.abort("First index must be a non-negative integer.")
if (!(j is Num && j.isInteger && j >= 0)) Fiber.abort("Second index must be a non-negative integer.")
if (!(s is String)) s = "%(s)"
if (i == j) return s
var chars = s.toList
var t = chars[i]
chars[i] = chars[j]
chars[j] = t
return chars.join()
}
}
Line 69 ⟶ 167:
// Converts an integer to a numeric ASCII string with a base between 2 and 36.
static itoa(n, b) {
if (!(n is Num && n.isInteger) ||&& n.abs ><= maxSafeInt)) Fiber.abort("Argument must be a safe integer.")
if (b < 2 || b > 36) Fiber.abort("Base must be between 2 and 36.")
if (n == 0) return "0"
Line 154 ⟶ 252:
}
 
/* Fmt contains some routines towhich format numbers or strings in various ways. */
class Fmt {
// Left justifies 's' in a field of minimum width 'w' using the pad character 'p'.
static lpadljust(w, s, p) {
if (!w.isInteger || w < 0) Fiber.abort("Width must be a non-negative integer.")
if (!(p is String) || p.count != 1) Fiber.abort("Padder must be a single character string.")
Line 166 ⟶ 264:
 
// Right justifies 's' in a field of minimum width 'w' using the pad character 'p'.
static rpadrjust(w, s, p) {
if (!w.isInteger || w < 0) Fiber.abort("Width must be a non-negative integer.")
if (!(p is String) || p.count != 1) Fiber.abort("Padder must be a single character string.")
Line 172 ⟶ 270:
var c = s.count
return (w > c) ? p * (w - c) + s : s
}
 
// Right justifies 's' in a field of minimum width 'w' using the pad character '0'.
// Unlike rpad, any sign or elided sign (i.e. space) will be placed before the padding.
// Should normally only be used with numbers or numeric strings.
static rzpad(w, s) {
if (!w.isInteger || w < 0) Fiber.abort("Width must be a non-negative integer.")
if (!(s is String)) s = "%(s)"
var c = s.count
if (w <= c) return s
var sign = (c > 0 && (s[0] == "-" || s[0] == "+" || s[0] == " ")) ? s[0] : ""
if (sign == "") return "0" * (w - c) + s
return sign + "0" * (w - c) + s[1..-1]
}
 
// Centers 's' in a field of minimum width 'w' using the pad character 'p'.
static cpadcjust(w, s, p) {
if (!w.isInteger || w < 0) Fiber.abort("Width must be a non-negative integer.")
if (!(p is String) || p.count != 1) Fiber.abort("Padder must be a single character string.")
Line 199 ⟶ 284:
 
// Convenience versions of the above which use a space as the pad character.
static lpadljust(w, s) { lpadljust(w, s, " ") }
static rpadrjust(w, s) { rpadrjust(w, s, " ") }
static cpadcjust(w, s) { cpadcjust(w, s, " ") }
 
// Right justifies 's' in a field of minimum width 'w' using the pad character '0'.
// Unlike rjust, any sign or elided sign (i.e. space) will be placed before the padding.
// Should normally only be used with numbers or numeric strings.
static zfill(w, s) {
if (!w.isInteger || w < 0) Fiber.abort("Width must be a non-negative integer.")
if (!(s is String)) s = "%(s)"
var c = s.count
if (w <= c) return s
var sign = (c > 0 && "-+ ".contains(s[0])) ? s[0] : ""
if (sign == "") return "0" * (w - c) + s
return sign + "0" * (w - c) + s[1..-1]
}
 
// Checks whether argument is a numeric decimal string.
static isDecimal(n) { n is String && n != "" && n.all { |c| "-0123456789".contains(c) } }
if (!(n is String && n != "" && "+- 0123456789".contains(n[0]))) return false
if ("-+ ".contains(n[0])) {
if (n.count == 1) return false
n = n[1..-1]
}
return n.all { |c| "0123456789".contains(c) }
}
 
// Adds 'thousand separators' to a decimal integer or string.
static commatize(n, c) {
Line 211 ⟶ 316:
if (!(c is String) || c.count != 1) Fiber.abort("Separator must be a single character string.")
if (n is Num) n = "%(Conv.dec(n))"
var negsigned = "-+ ".contains(n[0] == "-")
ifvar (neg) nsign = n[1..-1]""
if (signed) {
sign = n[0]
n = n[1..-1]
}
if (n.startsWith("0") && n != "0") {
n = n.trimStart("0")
Line 222 ⟶ 331:
i = i - 3
}
return (negsigned) ? "-"sign + n : n
}
 
// Convenience version of the above method which uses a comma as the separator.
static commatize(n) { commatize(n, ",") }
 
// Convenience method which commatizes an ordinal number using a comma as the separator.
static ordinalize(n) { commatize(n) + Conv.ord(n)[-2..-1] }
 
// Abbreviates a string 's' to a maximum number of characters 'w' (non-overlapping) at either end
// or, if 'w' is negative from the front only, using 'sep' as the separator.
// Doesn't abbreviate a string unless at least one character would need to be suppressed.
static abbreviate(w, s, sep) {
if (!(w is Num && w.isInteger && w.abs >= 1)) Fiber.abort("Maximum width must be a non-zero integer.")
if (!(sep is String)) Fiber.abort("Separator must be a string.")
if (!(s is String)) s = "%(s)"
var c = s.count
if (c <= ((w < 0) ? -w : 2*w)) return s
var le = (w >= 0) ? w : -w
return Str.sub(s, 0...le) + sep + ((w >= 0) ? Str.sub(s, -le..-1) : "")
}
 
// Convenience version of the above method which uses 'three dots' as the separator.
static abbreviate(w, s) { abbreviate(w, s, "...") }
 
// Gets or sets precision for 'f(w, n)' convenience method.
static precision { ( __precision != null) ? __precision : 6 }
static precision=(p) { __precision = ((p is Num) && p.isInteger && p >= 0) ? p : __precision }
 
Line 237 ⟶ 365:
// Pads with spaces to a minimum width of 'w'.
// Negative 'w' left justifies, non-negative 'w' right justifies.
static d(w, n) { (w >= 0) ? rpadrjust(w, Conv.dec(n)) : lpadljust(-w, Conv.dec(n)) }
static b(w, n) { (w >= 0) ? rpadrjust(w, Conv.bin(n)) : lpadljust(-w, Conv.bin(n)) }
static o(w, n) { (w >= 0) ? rpadrjust(w, Conv.oct(n)) : lpadljust(-w, Conv.oct(n)) }
static x(w, n) { (w >= 0) ? rpadrjust(w, Conv.hex(n)) : lpadljust(-w, Conv.hex(n)) }
static X(w, n) { (w >= 0) ? rpadrjust(w, Conv.Hex(n)) : lpadljust(-w, Conv.Hex(n)) }
 
// As above but pads with leading zeros instead of spaces.
// Any minus sign will be placed before the padding.
// When used with negative 'w' behaves the same as the above methods.
static dz(w, n) { (w >= 0) ? rzpadzfill(w, Conv.dec(n)) : lpadljust(-w, Conv.dec(n)) }
static bz(w, n) { (w >= 0) ? rzpadzfill(w, Conv.bin(n)) : lpadljust(-w, Conv.bin(n)) }
static oz(w, n) { (w >= 0) ? rzpadzfill(w, Conv.oct(n)) : lpadljust(-w, Conv.oct(n)) }
static xz(w, n) { (w >= 0) ? rzpadzfill(w, Conv.hex(n)) : lpadljust(-w, Conv.hex(n)) }
static Xz(w, n) { (w >= 0) ? rzpadzfill(w, Conv.Hex(n)) : lpadljust(-w, Conv.Hex(n)) }
 
// Formats 'n' in decimal, space padded, with a leading '+' if 'n' is non-negative or '-' otherwise.
static dp(w, n) { (w >= 0) ? rpadrjust(w, Conv.pdec(n)) : lpadljust(-w, Conv.pdec(n)) }
 
// Formats 'n' in decimal, space padded, with a leading ' ' if 'n' is non-negative or '-' otherwise.
static dm(w, n) { (w >= 0) ? rpadrjust(w, Conv.mdec(n)) : lpadljust(-w, Conv.mdec(n)) }
 
// Formats 'n' in commatized form, space padded, using ',' as the separator
static dc(w, n) { (w >= 0) ? rpadrjust(w, commatize(Conv.dec(n))): lpadljust(-w, commatize(Conv.dec(n))) }
 
// Pads a string or value 'v' with spaces to a minimum width of 'w'.
// Negative 'w' left justifies, non-negative 'w' right justifies.
static s(w, v) { (w >= 0) ? rpadrjust(w, v) : lpadljust(-w, v) }
 
// Centers a string or value 'v' within a field of minimum width 'w'. Pads with spaces.
static c(w, v) { cpadcjust(w, v) }
 
// Embeds a string or value 'v' in double quotes.
Line 300 ⟶ 428:
// Any minus sign will be placed before the padding.
// When used with negative 'w' behaves the same as the above method.
static fz(w, n, p) { (w >= 0) ? rzpadzfill(w, f(w, n, p).trimStart()) : f(w, n, p) }
 
// Convenience versions of the above methods which use the default precision.
9,485

edits