rs-0.16.0 — Random numbers, regular expressions, and raw strings#
Two new standard packages: std.random for dice, cards,
shuffles, weighted picks, and repeatable seeds, and std.regex
for finding, checking, replacing, and splitting text by pattern. Raw strings,
r"...", keep backslashes as they are written, so patterns read plainly.
std.random#
takepkg std.random;
func m{
out(random.int_between(1, 6)); // a dice roll
deck = arr("A", "K", "Q", "J", "10");
random.shuffle(deck);
out(random.sample(deck, 2)); // two different cards
out(random.weighted_choice(arr("common", "rare", "epic"), arr(80, 15, 5)));
}
| Function | Result |
|---|---|
float(), float_between(low, high) |
A float, from 0.0 or low up to, but never, 1.0 or high |
int_between(low, high), int_below(count) |
A whole number, every value equally likely |
bool(), chance(probability) |
true half the time, or with that probability |
choice, choices, sample |
One item; several, repeats allowed; several from different positions |
shuffle, shuffled |
A random order, in place or as a copy |
weighted_choice, weighted_choices |
Picks in proportion to weights |
gauss(mean, deviation) |
The normal distribution |
seed(seed), Generator(seed) |
Repeatable numbers; a generator of its own |
After random.seed(42), or a string seed such as random.seed("level-1"), a
program makes the same numbers on every run and on every platform: the tests
check exact sequences on Windows, macOS, and Linux, on x86 and ARM.
random.Generator(seed) gives one part of a program numbers of its own, so a
procedural world stays the same however many dice the rest of the game rolls.
The generator is xoshiro256++, Julia's default and the one behind Rust's
SmallRng, with Lemire's method for ranges, so no value is favoured. It is the
only native part; shuffling, sampling, weights, and the normal distribution
are Marslang, in std/random.mars. It is not for passwords or keys.
std.regex#
takepkg std.regex;
func m{
out(regex.matches(r"\d{4}-\d{2}-\d{2}", "2026-10-12")); // true
date = regex.find_whole(r"(?<year>\d{4})-(?<month>\d{2})-(\d{2})", "2026-10-12");
out(date.named("year"), date.group(3)); // 2026 12
for (tag, regex.find_all(r"#(\w+)", "#rust and #mars")){ out(tag.group(1)); }
out(regex.replace(r"(\w+)@(\w+)", "ada@home", "$2:$1")); // home:ada
out(regex.split(r"\s*,\s*", "a , b,c")); // ["a", "b", "c"]
}
matches, contains, find, find_all, find_whole, replace,
replace_first, replace_with (a function makes each replacement), split,
and escape, with a Match for each match (its text, character positions,
numbered and named groups) and Regex(pattern) to check a pattern once and
pass it around. Patterns are compiled on first use and kept.
Matching is Rust's regex crate, which takes time in proportion to the text for
every pattern: no pattern can hang a program, so patterns and text from users
are safe. In return, backreferences (\1) and lookaround ((?=...)) are not
supported, and say so. A pattern with a mistake raises a SyntaxError on one
line that says where: regex "ab(c" at character 3: unclosed group.
Positions count characters, as len and slice do, so
text.slice(m.start, m.end) is always the match, even after emoji.
Raw strings#
pattern = r"\d+(\.\d+)?"; // the same as "\\d+(\\.\\d+)?"
folder = r"C:\Users\ada\new"; // \n is not a line break here
An r before the opening quote makes a raw string, in which a backslash is
only a backslash: r"...", r'...', and r"""...""" over several lines. In an
ordinary string a backslash before a character with no escape of its own stands
for that character, so "\d" is just d, and a pattern written that way looks
for the letter. See raw strings.
The VS Code extension 0.3.5 colours raw strings, and no longer marks the
escapes \b, \f, \v, \xHH, and \u{...} as mistakes.
Validation#
cargo test passes 167 tests on Linux (20 unit, 146 execution, 1 memory) and
165 on Windows, including exact seeded sequences, fairness checks over
thousands of draws, regex positions around emoji and combining accents, and
every error message. Every push runs them on Windows, macOS, and Linux on x86_64
and ARM64, and runs the static Linux binary inside Alpine, Debian 11, Ubuntu
20.04, Rocky Linux 8, and Amazon Linux 2.