We just released cl-str v0.21. It’s been a while since the last release, and many enhancements make it more useful than ever. Let’s review the changes, the newest first.
But first, I want to you thank everyone who contributed, by sending pull requests or feedback. Special thanks to @kilianmh who suddenly appeared one day, helped with new features as well as grunt work, and who is now a co-maintainer.
split
by regex
The latest addition sent by ccQpein is that str:split
now accepts a :regex
key argument to split by regular expressions. The functions rsplit
and split-omit-nulls
have it too.
(str:split "[,|;]" "foo,bar;baz" :regex t)
;; => ("foo" "bar" "baz")
That’s handy for advent of code ;)
You can also use ppcre:split
, this is the function that str:split
relies on anyways, except that by default, str:split
ensures that the split argument is not a regex. We need this:
(ppcre:split `(:sequence ,(string separator)) s …)
(and eventually, we remove null elements if :omit-nulls t
was set)
replace by regex
str:replace-all
, str:replace-first
and str:replace-using
got a :regex
keyword too:
(str:replace-all "(?i)fo+" "frob" "FOO bar FOO" :regex t)
;; => "frob bar frob"
The ensure
functions
These were added in March.
The “ensure-” functions return a string that has the specified prefix or suffix, appended if necessary.
ensure
encapsulates the other two.
ensure-prefix, ensure-suffix (start/end s)
Ensure that s
starts with start/end
(or ends with start/end
, respectively).
Return a new string with its prefix (or suffix) added, if necessary.
Example:
(str:ensure-prefix "/" "abc/") => "/abc/" (a prefix was added)
;; and
(str:ensure-prefix "/" "/abc/") => "/abc/" (does nothing)
We also have a couple functions to find the prefixes or the suffixes, please see our README.
ensure-wrapped-in (start/end s)
Ensure that s
both starts and ends with start/end
.
Return a new string with the necessary added bits, if required.
It simply calls str:ensure-suffix
followed by str:ensure-prefix
.
See also str:wrapped-in-p
and uiop:string-enclosed-p prefix s suffix
.
(str:ensure-wrapped-in "/" "abc") ;; => "/abc/" (added both a prefix and a suffix)
(str:ensure-wrapped-in "/" "/abc/") ;; => "/abc/" (does nothing)
ensure (s &key wrapped-in prefix suffix)
This str:ensure
function looks for the following key parameters, in order:
:wrapped-in
: if non nil, callstr:ensure-wrapped-in
. This checks thats
both starts and ends with the supplied string or character.:prefix
and:suffix
: if both are supplied and non-nil, callstr:ensure-suffix
followed bystr:ensure-prefix
.:prefix
: callstr:ensure-prefix
:suffix
: callstr:ensure-suffix
.
Example:
(str:ensure "abc" :wrapped-in "/") ;; => "/abc/"
(str:ensure "/abc" :prefix "/") ;; => "/abc" => no change, still one "/"
(str:ensure "/abc" :suffix "/") ;; => "/abc/" => added a "/" suffix.
These functions accept strings and characters:
(str:ensure "/abc" :prefix #\/)
warn: if both :wrapped-in
and :prefix
(and/or :suffix
) are supplied together, :wrapped-in
takes precedence and :prefix
(and/or :suffix
) is ignored.
:char-bag
parameter to trim, trim-left, trim-right
This was added in January.
str:trim
removes all characters in char-bag
(default: whitespaces) at the beginning and end of s
.
If supplied, char-bag
has to be a sequence (e.g. string or list of characters).
(str:trim "cdoooh" :char-bag (str:concat "c" "d" "h")) => "ooo"
fit a string to some length
This is older, it was added in February of 2022.
Fit this string to the given length:
- if it’s too long, shorten it (showing the
ellipsis
), - if it’s too short, add paddding (to the side
pad-side
, adding the characterpad-char
).
As such, it accepts the same key arguments as str:shorten
and
str:pad
: ellipsis
, pad-side
, pad-char
…
CL-USER> (str:fit 10 "hello" :pad-char "+")
"hello+++++"
CL-USER> (str:fit 10 "hello world" :ellipsis "…")
"hello wor…"
If, like me, you want to print a list of data as a table, see:
CL-USER> (ql:quickload "cl-ansi-term")
CL-USER> (term:table '(("name" "age" "email")
("me" 7 "some@blah")
("me" 7 "some@with-some-longer.email"))
:column-width '(10 4 20))
+---------+---+-------------------+
|name |age|email |
+---------+---+-------------------+
|me |7 |some@blah |
+---------+---+-------------------+
|me |7 |some@with-some-l(…)|
+---------+---+-------------------+
CL-USER> (ql:quickload "cl-ascii-table")
CL-USER> (let ((table (ascii-table:make-table '("Id" "Name" "Amount") :header "Infos")))
(ascii-table:add-row table '(1 "Bob" 150))
(ascii-table:add-row table '(2 "Joe" 200))
(ascii-table:add-separator table)
(ascii-table:add-row table '("" "Total" 350))
(ascii-table:display table))
.---------------------.
| Infos |
+----+-------+--------+
| Id | Name | Amount |
+----+-------+--------+
| 1 | Bob | 150 |
| 2 | Joe | 200 |
+----+-------+--------+
| | Total | 350 |
+----+-------+--------+
NIL
fixed string-case
The str:string-case
macro was missing an implicit progn, so with more
than one s-expression in the clauses, it didn’t fail… but it didn’t work
as expected either.
Fixed for LispWorks
Characters are named differently, like #\NewLine
. We are still awaiting input on one issue.
We reimplemented str:replace-using
to fix it on LispWorks.
Misc
We added type declaration e.g. for concat
, join
.
str:ends-with-p
now works with a character.
Small breaking change: fixed str:prefixp
when used with a smaller prefix: “f” was not recognized as a prefix of “foobar” and “foobuz”, only “foo” was. Now it is fixed. Same for str:suffixp
.
We added str:ascii-p
and str:ascii-char-p
(in 2021).
More functions now work with characters as well.
We sped up str:join
(measured: 4x). We use with-output-to-string
and a loop instead of format
’s iteration directive.
We use uninterned symbols in defpackage.
We deprecated predicates ending with “?” (but they are still there).
We made casing-functions consistent to inbuilt cl casing functions (we use cl-change-case
, but the functions also allow symbols and characters (not only strings) and return NIL when given NIL).
We added :ignore-case
to str:count-substring
.
We switched the testing framework from prove to fiveam (that was grunt work by the new maintainer yay o/ )
That’s it, thanks again for helping make this lil’ lib useful since day 1.
The “str” library defines many more functions. Look at our table of content on the README: https://github.com/vindarel/cl-str
Install it with
(ql:quickload "str")