Text and Collections
● Intermediate3 minBefore this: Strings, ListsSpec 14.9
std.text and std.collections hold small helpers for text and lists: padding, words, chunks, pairs, counts. They are written in Kavach itself.
Text
use std.text
fn main() {
print("[{text.pad_left("42", 6, '0')}]")
print("[{text.pad_right("pens", 8, '.')}]")
print(text.words(" red\tgreen\n blue "))
print(text.capitalize("asha"))
print(text.truncate("a very long title", 6))
print(text.is_blank(" \t\n"))
}The program ran and printed:
kavach run helpers.kav
[000042][pens....]["red", "green", "blue"]Ashaa verytrue
To find numbers inside text, see Strings to numbers.
Text that looks the same
One letter can be written with different code points: é as one, or as e and an accent that joins it. Text typed on one machine and pasted from another can look the same and still not be equal. A Unicode normal form writes it one way, so both compare equal:
use std.text
fn main() {
const typed = "caf\u{E9}" // é as one code point
const pasted = "cafe\u{301}" // e, then an accent that joins it
print(typed == pasted)
print(text.nfc(typed) == text.nfc(pasted))
print("{typed.len()} {pasted.len()}")
print(text.nfkc("\u{FB01}le \u{FF11}\u{FF12}"))
}The program ran and printed:
kavach run normal-forms.kav
falsetrue4 5file 12
lencounts code points, so the two spellings ofcaféhave 4 and 5.nfcjoins a letter and its accent;nfdsplits them.nfkcandnfkdalso turn look-alike characters into plain ones:fiintofi, the full-width12into12.- To compare what people type, such as user names, passwords and searches, normalise both sides first.
Lists
use std.collections
fn main() {
const items = ["pen", "ink", "pen", "pad", "pen"]
print(collections.chunks([1, 2, 3, 4, 5], 2))
print(collections.zip(["a", "b", "c"], [1, 2]))
print(collections.unique(items))
print(collections.counts(items))
print(collections.flatten([[1, 2], [], [3]]))
}The program ran and printed:
kavach run helpers.kav
[[1, 2], [3, 4], [5]][("a", 1), ("b", 2)]["pen", "ink", "pad"]["pen": 3, "ink": 1, "pad": 1][1, 2, 3]
zipstops at the shorter list, so"c"has no pair.uniqueandcountskeep the order in which items were first seen.
Every function
| Function | Gives |
|---|---|
text.pad_left(s, width, fill), text.pad_right(s, width, fill) | s filled with fill (a Char, default ' ') up to width characters |
text.words(s) | The words of s: the parts between runs of spaces, tabs and line breaks |
text.capitalize(s) | s with its first character in upper case |
text.truncate(s, max) | At most max characters of s |
text.is_blank(s) | Whether s has only spaces, tabs and line breaks |
text.find_ints(s) | Every whole number written inside s, in order: "a12b34" gives [12, 34] |
text.find_int(s) | The first of them, or none: "sd23" gives 23 |
text.find_float(s) | The first number with its fraction, or none: "pi is 3.14!" gives 3.14 |
text.nfc(s), text.nfd(s), text.nfkc(s), text.nfkd(s) | s in a Unicode normal form (UAX #15), so texts written with different code points compare equal: nfc joins a letter and its accent into one code point, nfd splits them, and the k forms also turn compatibility characters into plain ones (fi into fi, full-width 1 into 1). The runtime gives these four (decision 0102); the rest of std.text is written in Kavach |
collections.chunks(items, size) | The items in lists of size (the last may be shorter) |
collections.zip(a, b) | Pairs of items at the same position, as long as the shorter list |
collections.unique(items) | Each item once, in the order first seen |
collections.counts(items) | How many times each item appears, in the order first seen |
collections.flatten(lists) | The items of all the lists, in order |
Both modules are written in Kavach, with contracts and examples like any other code, so kavach test checks them too. The four normal forms are the exception: the runtime gives them, from Unicode's own tables.