Reader macros
Loading Consfigurator defines the :CONSFIGURATOR
named readtable. Its
original purpose was to define a few reader macros to make Lisp more readily
usable for Unix systems administration, and as such it’s helpful in consfigs.
We now have the broader aim of providing a readtable that renders Lisp more
useful for general Unix-style text manipulation. To this end, the reader
macros we define are all inspired by Perl syntax.
Backwards compatibility
We don’t expect to make incompatible changes to how these reader macros work, except to make them work more like their Perl equivalents. With this in mind, some particular reservations are made for particular macros, as detailed below.
#?
: Regexps & interpolation
Sharp-question mark is the well-known CL-INTERPOL reader macro.
#~m//
: PCRE matching
This provides an abbreviation for shell- and Perl-style regexp matching:
(#~m/b.+b/i "FooBarBaz") => "BarB"
(#~m/b(.+)b/i "FooBarBaz") => #("ar")
(mapcar #3~m/(\w+)(\W+)(\w+)/ '("one two" "three four" "five six"))
=> ("two" "four" "six")
Any delimiters supported by CL-INTERPOL
may be used, and the m
is
always optional. Standard trailing options g
, i
, m
, s
and
x
are meaningful. There is also p
, which means to attempt to parse
the matched strings and substrings as numbers; if a substring cannot be parsed
as a number, it is returned unmodified.
The return value depends on the numeric argument before the tilde:
#~m//
, with no argument, returns a vector of the substrings corresponding to the capture groups, or if there were no capture groups, just the whole matched string.#0~m//
returns two values: the whole matched string, and a vector of capture group substrings. (This is plainCL-PPCRE:SCAN-TO-STRINGS
.)#n~m//
returns two values: the nth capture group’s substring, and a vector of all the capture group substrings.
#!~m//
: PCRE negative matching
Equivalent to (not #~m//)
.
#~s///
: PCRE substitution
This provides an abbreviation for shell- and Perl-style regexp substitution:
(#~s/foo/bar/ "foobarbaz") => "foofoobaz"
(mapcar #~s/:.+:/`\&`/ '(":Hello:" ":Goodbye:")) => ("`:Hello:`" "`:Goodbye:`")
Again, any delimiters supported by CL-INTERPOL
may be used, and the same
trailing options, except for p
, are meaningful. This is
CL-PPCRE:REGEX-REPLACE
or CL-PPCRE:REGEX-REPLACE-ALL
, which see
regarding return values.
#>EOF>
and #>>EOF>>
: Heredocs
Following #>EOF>
, all characters are read into a string until the next
literal EOF
. You may use any string in place of EOF
, except that it
must not begin with a tilde or contain any whitespace, and for the sake of
future extension, it must not begin with a backwards slash or begin or end
with single or double quotation marks.
You can double up the >
, as in #>>EOF>>
, to skip the remainder of the
line on which the #>>EOF>>
appears, starting the heredoc at the beginning
of the following line. For the sake of future extension, the remainder of the
line after the #>>EOF>>
must not contain anything other than a single-line
comment.
The specification of the terminating string may be preceded by a tilde, as in
#>>~EOF>>
, to mean an indented heredoc:
(foo "argument 1" #>>~EOF>>
My line 1.
My line 2.
EOF)
The function receives "My line 1.\nMy line 2.\n"
.
See also
Let Over Lambda ch. 4, which originally inspired
#~m//
and#~s///
.