Category talk:Fmt: Difference between revisions
Content added Content deleted
(→Source code: Fixed some bugs, lots of improvements. Hopefully fairly stable now.) |
(→Source code: Module reorganization - moving Str class to new 'str' module.) |
||
Line 2: | Line 2: | ||
<lang ecmascript>/* Module "fmt.wren" */ |
<lang ecmascript>/* Module "fmt.wren" */ |
||
/* Str contains routines which manipulate strings in various ways. */ |
|||
class Str { |
|||
// Converts a string to lower case. |
|||
static lower(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 |
|||
} |
|||
return cps.reduce("") { |acc, c| acc + String.fromCodePoint(c) } |
|||
} |
|||
// Converts a string to upper case. |
|||
static upper(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 >= 97 && c <= 122) cps[i] = c - 32 |
|||
} |
|||
return cps.reduce("") { |acc, c| acc + String.fromCodePoint(c) } |
|||
} |
|||
// Swaps the case of each character in a string. |
|||
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)" |
|||
if (s == "") return s |
|||
var cps = s.codePoints.toList |
|||
var start = (s.startsWith("[") && cps.count > 1) ? 1 : 0 |
|||
var c = cps[start] |
|||
if (c >= 97 && c <= 122) { |
|||
cps[start] = c - 32 |
|||
return cps.reduce("") { |acc, c| acc + String.fromCodePoint(c) } |
|||
} |
|||
return s |
|||
} |
|||
// Capitalizes the first character of each word of a string. |
|||
static title(s) { |
|||
if (!(s is String)) s = "%(s)" |
|||
if (s == "") return s |
|||
var words = s.split(" ") |
|||
return words.map { |w| capitalize(w) }.join(" ") |
|||
} |
|||
// Reverses the characters (not necessarily single bytes) of a string. |
|||
static reverse(s) { |
|||
if (!(s is String)) s = "%(s)" |
|||
return (s != "") ? s[-1..0] : s |
|||
} |
|||
// 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() |
|||
} |
|||
} |
|||
/* Conv contains routines which do conversions between types. */ |
/* Conv contains routines which do conversions between types. */ |
||
Line 179: | Line 25: | ||
return ((neg) ? "-" : "") + res[-1..0] |
return ((neg) ? "-" : "") + res[-1..0] |
||
} |
} |
||
// Private helper function. Converts ASCII string to upper case. |
|||
static upper_(s) { s.bytes.map { |b| |
|||
return String.fromByte((b >= 97 && b <= 122) ? b - 32 : b) |
|||
}.join() } |
|||
// As itoa(n, b) but resulting digits are upper case. |
// As itoa(n, b) but resulting digits are upper case. |
||
static Itoa(n, b) { (b < 11) ? itoa(n, b) : |
static Itoa(n, b) { (b < 11) ? itoa(n, b) : upper_(itoa(n, b)) } |
||
// Converts a numeric ASCII string with a base between 2 and 36 to an integer. |
// Converts a numeric ASCII string with a base between 2 and 36 to an integer. |
||
Line 195: | Line 46: | ||
} |
} |
||
if (s == "") Fiber.abort("String must contain some digits.") |
if (s == "") Fiber.abort("String must contain some digits.") |
||
s = |
s = upper_(s) |
||
if ((s.startsWith(" |
if ((s.startsWith("0B") && b != 2) || (s.startsWith("0O") && b != 8) || (s.startsWith("0X") && b != 16)) { |
||
Fiber.abort("Inconsistent base specifier.") |
Fiber.abort("Inconsistent base specifier.") |
||
} |
} |
||
if (s.startsWith(" |
if (s.startsWith("0B") || s.startsWith("0O") || s.startsWith("0X")) { |
||
s = s[2..-1] |
s = s[2..-1] |
||
if (s == "") Fiber.abort("String after base specifier must contain some digits.") |
if (s == "") Fiber.abort("String after base specifier must contain some digits.") |
||
Line 301: | Line 152: | ||
} |
} |
||
// Private helper method for 'commatize' method. |
|||
// Checks whether argument is a numeric decimal string. |
// Checks whether argument is a numeric decimal string. |
||
static |
static isDecimal_(n) { |
||
if (!(n is String && n != "" && "+- 0123456789".contains(n[0]))) return false |
if (!(n is String && n != "" && "+- 0123456789".contains(n[0]))) return false |
||
if ("-+ ".contains(n[0])) { |
if ("-+ ".contains(n[0])) { |
||
Line 340: | Line 192: | ||
static ordinalize(n) { commatize(n) + Conv.ord(n)[-2..-1] } |
static ordinalize(n) { commatize(n) + Conv.ord(n)[-2..-1] } |
||
// Private helper method for 'abbreviate' method. |
|||
static sub_(s, r) { s.toList[r].join() } |
|||
// Abbreviates a string 's' to a maximum number of characters 'w' (non-overlapping) at either end |
// 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. |
// or, if 'w' is negative from the front only, using 'sep' as the separator. |
||
Line 350: | Line 205: | ||
if (c <= ((w < 0) ? -w : 2*w)) return s |
if (c <= ((w < 0) ? -w : 2*w)) return s |
||
var le = (w >= 0) ? w : -w |
var le = (w >= 0) ? w : -w |
||
return |
return sub_(s, 0...le) + sep + ((w >= 0) ? sub_(s, -le..-1) : "") |
||
} |
} |
||
Line 436: | Line 291: | ||
// Type aliases for classes in case of any name clashes with other modules. |
// Type aliases for classes in case of any name clashes with other modules. |
||
var Fmt_Str = Str |
|||
var Fmt_Conv = Conv |
var Fmt_Conv = Conv |
||
var Fmt_Fmt = Fmt</lang> |
var Fmt_Fmt = Fmt</lang> |