(std scan)

Reference

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.

See also: scan, try-scan

Reference

Functions

Macros

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