A modern and consistent Common Lisp string manipulation library
modernity, simplicity and discoverability:
(str:trim s)instead of
(string-trim '(#\Space #\Newline #\Backspace #\Tab #\Linefeed #\Page #\Return #\Rubout) s)), or
str:concat stringsinstead of an unusual
formatconstruct; one discoverable library instead of many;
consistance and composability, where
sis always the last argument, which makes it easier to feed pipes and arrows.
The only dependency is
Table of Contents
- A modern and consistent Common Lisp string manipulation library
- Global parameters
- Tweak whitespace
- To longer strings
- To shorter strings
- To and from lists
- To and from files (experimental in v0.4)
- Dev and test
- See also
Install with Quicklisp:
Check its version:
To get a newer version, you need to update the Quicklisp dist (think of QL as Debian's apt rather than pip/npm/etc):
beware, this is a young and unstable library. (update v0.7) The functions implementation may change, but we shouldn't change the api.
(don't have a full Common Lisp development environment yet ? Get Portacle, a portable and multiplatform development environment shipping Emacs, Quicklisp, SBCL and Git).
Some parameters are common to various functions and often used:
Consequently we can also manage them with global parameters:
(let ((*ignore-case* t)) (ends-with? "BAR" "foobar"))
is equivalent to
(ends-with? "BAR" "foobar" :ignore-case t)
Remove whitespaces at the beginning and end of
(trim " rst ") ;; => "rst"
Uses the built-in
where whitespaces are
'(#\Space #\Newline #\Backspace #\Tab #\Linefeed #\Page #\Return #\Rubout).
To longer strings
Join strings in list
separator in between.
(join " " '("foo" "bar" "baz")) ;; => "foo bar baz"
Uses a specific format syntax.
Join strings into one.
(concat "f" "o" "o") ;; => "foo"
Simple call of the built-in concatenate.
We actually also have
Make a string of
(repeat 3 "foo") ;; => "foofoofoo"
(items s) (new in 0.9)
Respectively prepend or append
s to the front of each item.
To shorter strings
(start end s)
Return the substring of
subseq with differences:
- argument order, s at the end
endcan be lower than 0 or bigger than the length of s.
- for convenience
endcan be nil or t to denote the end of the string.
(is "abcd" (substring 0 t "abcd") "t denotes the end of the string") (is "abcd" (substring 0 nil "abcd") "nil too") (is "abcd" (substring 0 100 "abcd") "end can be too large") (is "abc" (substring 0 -1 "abcd") "end can be negative. Counts from the end.") (is "" (substring 0 -100 "abcd") "end can be negative and too low") (is "" (substring 100 1 "abcd") "start can be too big") (is "abcd" (substring -100 4 "abcd") "start can also be too low") (is "" (substring 2 1 "abcd") "start is bigger than end")
Return the first letter of
(s-first "foobar") ;; => "f" (s-first "") ;; => ""
Return the last letter of
Return the rest substring of
(s-rest "foobar") ;; => "oobar" (s-rest "") ;; => ""
Return the nth letter of
(s-nth 3 "foobar") ;; => "b" (s-nth 3 "") ;; => ""
You could also use
(elt "test" 1) ;; => #\e (string (elt "test" 1)) ;; => "e"
(len s &key ellipsis)
s is longer than
len, truncate it and add an ellipsis at the
... by default).
s is cut down to
len minus the length of
the ellipsis (3 by default).
Optionally, give an
:ellipsis keyword argument. Also set it globally
(prune 8 "hello world") ;; => "hello..." (prune 3 "hello world") ;; => "..." (prune 8 "hello world" :ellipsis "-") ;; => "hello w-" (let ((*ellipsis* "-")) (prune 8 "hello world")) ;; => "hello w-"
To and from lists
Return list of words, which were delimited by whitespace.
Join the list of strings with a whitespace.
Split string by newline character and return list of lines.
Join the list of strings with a newline character.
(separator s &key omit-nulls)
Split into subtrings (unlike cl-ppcre, without a regexp). If
omit-nulls is non-nil, zero-length substrings are omitted.
(split "+" "foo++bar") ;; => ("foo" "" "bar") (split "+" "foo++bar" :omit-nulls t) ;; => ("foo" "bar")
It is a wrapper around
cl-ppcre:split, so it comes
with its inconsistency when the separator appears at the end of
(cl-ppcre:split "," ",a,b,,c,") ;; => ("" "a" "b" "" "c")
it doesn't return a trailing
split-omit-nulls (in v0.6, QL january 2018)
Because it is a common pattern and it can be clearer than an option coming after many parenthesis.
To and from files (experimental in v0.4)
Read the file and return its content as a string.
:external-format: if nil, the system default. Can be bound to
But you might just call
There is also
Write the string
s to the file
filename. If the file does not
exist, create it, if it already exists, replace it.
Returns the string written to file.
s is nil or the empty string:
(empty? nil) ;; => T (empty? "") ;; => T (empty? " ") ;; => NIL
s is empty or only contains whitespaces.
(blankp "") ;; => T (blankp " ") ;; => T (emptyp " ") ;; => NIL
(start s &key ignore-case)
s starts with the substring
start, nil otherwise. Ignore
case by default.
(starts-with? "foo" "foobar") ;; => T (starts-with? "FOO" "foobar") ;; => NIL (starts-with? "FOO" "foobar" :ignore-case t) ;; => T
string-equal depending on the case, with their
(end s &key ignore-case)
s ends with the substring
end. Ignore case by default.
(ends-with? "bar" "foobar") ;; => T
(substring s &key (ignore-case nil))
Return true if
substring, nil otherwise. Ignore the
:ignore-case t (don't ignore by default).
Based on a simple call to the built-in
search (which returns the
position of the substring).
prefix?, prefixp and suffix?, suffixp
(items s) (new in 0.9)
s if it is a common prefix (or suffix) between items.
uiop:string-prefix-p prefix s, which returns
prefix is a prefix of
uiop:string-enclosed-p prefix s suffix, which returns
prefix and ends with
(old new s)
new (no regexs) in
(replace-all "a" "o" "faa") ;; => "foo"
Uses cl-ppcre:regex-replace-all but quotes the user input to not treat it as a regex.
(list-of-strings) (renamed in 0.9)
common-prefix in v0.9)
Find the common prefix between strings.
(str:prefix '(\"foobar\" \"foozz\")) => "foo"
Uses the built-in
mismatch, that returns the position at which
the strings fail to match.
Return a string or nil when the input is the void list.
(list-of-strings) (new in 0.9)
Find the common suffix between strings.
string-case (new in v0.8, Quicklisp end of february 2018)
A case-like macro that works with strings (CL's case only works with symbols).
(str:string-case input ("foo" (do something)) (nil (print "input is nil") (otherwise (print "non of the previous forms was caught.")))
You might also like pattern matching. The example below with optima is very similar:
(optima:match "hey" ("hey" (print "it matched")) (otherwise :nothing))
Note that there is also http://quickdocs.org/string-case/.
- 0.10 (Quicklisp end of august, 2018)
splitdoesn't fix cl-ppcre's inconsistency anymore (when the separator appears at the end). See issue #18. So
(str:split "xx" "fooxxbarxx")doesn't return a trailing
s-firstand friends return
nilwhen appropriate, not
- 0.9 (Quicklisp end of may, 2018)
suffixfunctions and predicates.
- 0.8 added
- 0.7 added
- 0.6 added
split-omit-nulls(QL, january 2018)
- 0.5 added
- 0.4 added
- 0.3 added
Dev and test
Test with prove.
- cl-strings, a similar (discovered afterwards), maybe more complete library, that does not use established libraries as dependencies as we do (with potential implementation issues).
- cl-change-case to convert strings between camelCase, param-case, snake_case and more.
- the Common Lisp Cookbook, strings page.
Inspired by the famous Emacs Lisp's s.el.