ascii
import ascii from "ascii";ascii answers questions about single bytes: is this a digit, a letter,
whitespace? It also converts letters between upper and lower case and gives
the value of a digit. It is a pure t0 module: it allocates nothing, has no
state, and works in every profile.
Every function takes a u8 and accepts all 256 values. Bytes from 128 up
are never in any class and are never changed by the case functions, so you
can run them over UTF-8 text byte by byte without damaging multi-byte
characters.
tape has no character literals, so the examples write bytes as numbers:
48 is '0', 65 is 'A', 97 is 'a'.
Classifying bytes
| Function | True for |
|---|---|
is_digit(c: u8) -> bool | 0 to 9 |
is_hex_digit(c: u8) -> bool | 0 to 9, a to f, A to F |
is_upper(c: u8) -> bool | A to Z |
is_lower(c: u8) -> bool | a to z |
is_alpha(c: u8) -> bool | a letter, either case |
is_alnum(c: u8) -> bool | a letter or a digit |
is_space(c: u8) -> bool | space, tab, newline, vertical tab (11), form feed (12), carriage return |
is_print(c: u8) -> bool | a printable character: space (32) through ~ (126) |
let a: bool = ascii.is_digit(55); // true: '7'
let b: bool = ascii.is_hex_digit(71); // false: 'G'
let c: bool = ascii.is_alnum(95); // false: '_'
let d: bool = ascii.is_space(9); // true: tab
let e: bool = ascii.is_print(127); // false: DEL
// Count the bytes that aren't whitespace
let words: []const u8 = " tape ";
var count: i64 = 0;
for (i in 0..words.len) {
if (!ascii.is_space(words[i])) { count = count + 1; }
}
// count == 4Changing case
| Function | Returns |
|---|---|
to_upper(c: u8) -> u8 | the upper-case letter for a to z; any other byte unchanged |
to_lower(c: u8) -> u8 | the lower-case letter for A to Z; any other byte unchanged |
let up: u8 = ascii.to_upper(97); // 65: 'a' -> 'A'
let low: u8 = ascii.to_lower(90); // 122: 'Z' -> 'z'
let same: u8 = ascii.to_upper(49); // 49: '1' is not a letterDigit values
pub fn digit_value(c: u8) -> ?u8;The value of c as a digit: 0 to 9 give 0 to 9, and letters give 10 to
35 (a and A are 10, z and Z are 35), which covers every base up to
36. Any other byte gives null. Whether the byte is a digit of your base
is a check on the value: below 16 for hexadecimal, below 10 for decimal.
let f: ?u8 = ascii.digit_value(102); // 15: 'f'
let none: ?u8 = ascii.digit_value(33); // null: '!'
// Parse a hexadecimal number; null if it is empty or not hex
fn parse_hex(s: []const u8) -> ?u64 {
if (s.len == 0) { return null; }
var v: u64 = 0;
for (i in 0..s.len) {
let d: u8 = ascii.digit_value(s[i]) or { return null; };
if (d >= 16) { return null; }
v = (v << 4) | (d as u64);
}
return v;
}
// parse_hex("ff") is 255, parse_hex("fg") is nullLast modified: