Overview
Reads a line by a pattern written as a quoted list, after OCaml’s Scanf.
(import (std scan))
(def (lo . hi) (scan "3-17" '(long "-" long))) ; 3L and 17L
(def (Tuple w h counts) (scan "12x5: 1 0 3" '(int "x" int ": " int ... #:sep " ")))
(try-scan "12y5" '(int "x" int))
;; (Err "scan: expected \"x\" at column 3 of \"12y5\"")
(scan "Ada Lovelace,36" '((until ",") "," int)) ; ("Ada Lovelace", 36)
(scan "20231015" '(int #:width 4 int #:width 2 int #:width 2)) ; (2023, 10, 15)
(scan "id 7: x" '((:skip word) " " int ": " word)) ; (7, "x")
A pattern is a quoted list of items, read in order from the start of the line. The whole line must match: after the last item, the line must end.
Items.
"text" matches the text exactly, except that a run of spaces in
it matches any amount of whitespace, none included, as a space does in
OCaml’s formats.
int, long and double read a number, with an
optional sign. A number too big for its type does not match.
char reads one character, word the characters up to
whitespace or the end, and rest the rest of the line, which may be
empty.
(chars ".#") reads one or more of the characters given. The
arguments are strings of ASCII characters and the classes :digit,
:lower, :upper, :alpha, :alnum and :hex.
In a string, a-z is all the characters from a to z;
a - at the start or the end of the string is itself.
(until ",") takes the same arguments, and reads the characters up
to one of them or the end of the line, none included. It does not read
the character it stops at, so a field and its separator are
(until ",") ",".
A list of items is a group, read in order.
item #:width 4 reads no more than 4 characters for the item, as
OCaml’s %4d does, so '(int #:width 4 int #:width 2) reads
"202310" as 2023 and 10. A width goes after int,
long, double, word, rest, chars and
until.
(:skip item ...) reads the items and gives no value, as OCaml’s
%_d does. Text that it skips is not copied or sliced, and a
repetition in it makes no vec.
item ... reads the item as many times as it matches, none
included, and item ... #:sep "," puts the separator between them.
A repetition also ends when a round of it reads no text, so
rest ... reads the rest once.
(:? item ...) reads the items if they match, and nothing if they do
not. (:or a b ...) reads the first choice that matches.
Values.
A number, a character, a word, rest, chars and
until read a value; a string and a :skip read none. A group’s value is its one value, or a
Tuple of its values. A repetition’s value is a Vec, and an
option’s an Option. Every choice of an :or must read a value
of the same type, or all must read none. The result of a scan is the
value of its items as one group, or unit when they read none. The
types come from the pattern, so (scan line '(int ","int)) is a
(Tuple int int).
Speed. The macro compiles the pattern into straight-line code
over the line’s bytes when the program is compiled. A pattern of numbers
and strings allocates nothing; a word or rest is a slice of the
line, which shares its bytes, and a repetition allocates its vec.
Not a regex. A scan does not search and does not backtrack into
an item: a repetition takes as many items as match, and an item that is
read is not read again in another way. Use (std rx) to find text
inside other text.
Reference
Functions
scan-lit
function ↑ Functions
(: scan-lit (-> string int string int))
Matches a literal at a position. What a pattern’s string compiles to.
s- The line.
pos- The byte position.
literal- The text to match.
- returns
- The position after the literal, or -1.
scan-byte
function ↑ Functions
(: scan-byte (-> string int int int))
Matches one ASCII character at a position. What a one-character string of a pattern compiles to.
s- The line.
pos- The byte position.
b- The code of the character.
- returns
- The position after the character, or -1.
scan-lit8
function ↑ Functions
(: scan-lit8 (-> string int long int int))
Matches an ASCII literal of 2 to 8 characters at a position, with one 64-bit compare.
s- The line.
pos- The byte position.
bytes- The literal's bytes, the first in the lowest byte.
length- The number of bytes.
- returns
- The position after the literal, or -1.
scan-ws
function ↑ Functions
(: scan-ws (-> string int int))
Skips whitespace at a position. What a run of spaces in a pattern compiles to.
s- The line.
pos- The byte position.
- returns
- The position after the whitespace.
scan-int
function ↑ Functions
(: scan-int (-> string int int (Tuple int int)))
Reads an int at a position.
s- The line.
pos- The byte position.
width- The most characters to read, or -1 for no limit.
- returns
- The int and the position after it, or a position of -1.
scan-long
function ↑ Functions
(: scan-long (-> string int int (Tuple long int)))
Reads a long at a position.
s- The line.
pos- The byte position.
width- The most characters to read, or -1 for no limit.
- returns
- The long and the position after it, or a position of -1.
scan-double
function ↑ Functions
(: scan-double (-> string int int (Tuple double int)))
Reads a double at a position.
s- The line.
pos- The byte position.
width- The most characters to read, or -1 for no limit.
- returns
- The double and the position after it, or a position of -1.
scan-char
function ↑ Functions
(: scan-char (-> string int (Tuple char int)))
Reads one character at a position.
s- The line.
pos- The byte position.
- returns
- The character and the position after it, or a position of -1 at the end.
scan-word
function ↑ Functions
(: scan-word (-> string int int int))
Finds the end of the characters up to whitespace or the end of the line.
s- The line.
pos- The byte position.
width- The most characters to read, or -1 for no limit.
- returns
- The position after the word, or -1 when there is none.
scan-rest
function ↑ Functions
(: scan-rest (-> string int int int))
Finds the end of the rest of the line.
s- The line.
pos- The byte position.
width- The most characters to read, or -1 for no limit.
- returns
- The end of the line, or the position after width characters.
scan-chars
function ↑ Functions
(: scan-chars (-> string int long long int int))
Finds the end of one or more characters of an ASCII set.
s- The line.
pos- The byte position.
low- Bit c is set for each character c below 64.
high- Bit c - 64 is set for each character c from 64 to 127.
width- The most characters to read, or -1 for no limit.
- returns
- The position after the run, or -1 when there is none.
scan-until
function ↑ Functions
(: scan-until (-> string int long long int int))
Finds the end of the characters up to one of an ASCII set, none included.
s- The line.
pos- The byte position.
low- Bit c is set for each character c below 64.
high- Bit c - 64 is set for each character c from 64 to 127.
width- The most characters to read, or -1 for no limit.
- returns
- The position of the first character of the set, or the end.
scan-until-byte
function ↑ Functions
(: scan-until-byte (-> string int int int int))
Finds the end of the characters up to one ASCII character, none included.
s- The line.
pos- The byte position.
stop- The code of the character.
width- The most characters to read, or -1 for no limit.
- returns
- The position of the character, or the end.
scan-slice
function ↑ Functions
(: scan-slice (-> string int int string))
The text between two positions, which shares the line’s bytes.
s- The line.
from- The first byte position.
to- The byte position after the text.
- returns
- The text.
scan-end?
function ↑ Functions
(: scan-end? (-> string int bool))
Whether a position is the end of the line.
s- The line.
pos- The byte position.
- returns
- #t at the end.
scan-fail
function ↑ Functions
(: scan-fail (-> string int string %a))
Raises the error of a line that does not match.
s- The line.
pos- The byte position where the line stops matching.
expected- What the pattern expected there.
- returns
- Nothing: it raises.
- raises
System.FormatException - Always.
scan-message
function ↑ Functions
(: scan-message (-> string int string string))
The message of a line that does not match.
s- The line.
pos- The byte position where the line stops matching.
expected- What the pattern expected there.
- returns
- The message: what was expected, at which column, and the line.
Macros
scan
macro ↑ Macros
(scan line pattern)
Reads a line by a pattern, and raises when the line does not match.
line- The text to read.
pattern- A quoted list of items, such as
'(int "," int). See the module's reference.
The value is what the pattern reads: one value, a Tuple of them, or
unit. When the line does not match, scan raises a
System.FormatException whose message says what was expected, at
which column, and the line.
(def (x . y) (scan "7,1" '(long "," long)))
(scan "[.##.]" '("[" (chars ".#") "]")) ; ".##."
See also: try-scan
try-scan
macro ↑ Macros
(try-scan line pattern)
Reads a line by a pattern, as a Result.
line- The text to read.
pattern- A quoted list of items. See the module's reference.
The value is Ok with the values scan would answer, or
Err with the message scan would raise. A line that does not
match costs no exception.
(match (try-scan line '(int "x" int ": " int ... #:sep " "))
((Ok (Tuple w h counts)) (fits? w h counts))
((Err _) #f))
See also: scan