cl-strings is a small, portable, dependency-free set of utilities that make it
even easier to manipulate text in Common Lisp.
It has 100% test coverage and works at least on sbcl, ecl, ccl, abcl and clisp.
This section assumes you use quicklisp. If you don't, you should! Download and learn about it here.
Once you have quicklisp loaded, simply do:
(ql:quickload :cl-strings)
And it's all up and running. To run the tests do:
(ql:quickload :cl-strings-tests)
Please report if any tests fail in your Common Lisp implementation.
> (ql:quickload :cl-strings)
(:CL-STRINGS)
> (use-package :cl-strings)
T
> (defparameter *num* (parse-number "-3.1e3"))
*NUM* ;; -3100.0
> (format-number *num* :precision 3 :decimal-separator "." :order-separator ",")
"-3,100.000"
parse-number returns a number from a string, without using the reader (CL has parse-integer but no equivalent for other number types). It accepts integers, floats, fractional and scientific notations. It also accepts both chars and one character strings for the separators. This method may signal parse-error.
(parse-number "-3.1e2") ;; -310.0
(parse-number "1 234,9" :decimal-separator "," :order-separator " ") ;; 1234.9
format-number returns a string from a number. It's possible to set the precision (decimals), and the separators as chars or strings of length one.
(format-number 1234.326 :precision 2 :decimal-separator "," :order-separator " ") ;; "1 234,33"
make-template-parser returns a function (a closure actually) that can substitute known variables for their values. start-delimiter and end-delimiter define the template tags. ignore-case defaults to nil and can be set to change the way the returned function tests variable names. The argument list of the returned lambda is (string values) where string is the template and values is an association list. It is easier by example:
(defvar *my-parser* (make-template-parser "{{" "}}")) ;; closure
(funcall *my-parser* "Hello {{name}}!" '(("name" . "Sam"))) ;; "Hello Sam!"
starts-with checks if string starts with prefix. The key argument ignore-case defaults to nil.
(starts-with "fOo bar" "foo" :ignore-case t) ;; t
ends-with checks if string ends with suffix. The key argument ignore-case defaults to nil.
(ends-with "fOo bar" "bAr" :ignore-case t) ;; t
clean-diacritics returns a string with the diacritical characters replaced by their closest counterparts.
(clean-diacritics "Déjà vu") ;; "Deja vu"
shorten returns a string consisting of string cut off to length len, and then truncate-string (which defaults to "..." but can be nil or "") appended to it.
(shorten "and then the guy bit the dog!" 8) ;; "and then..."
replace-all returns a string with every instance of part replaced by replacement in string. ignore-case defaults to nil.
(replace-all "Fo3sale: baby shoes, neve3worn" "3" "r ")
;; "For sale: baby shoes, never worn"
join receives a list of strings and concatenates them. They can be delimited by separator.
(join (list "Woot" "woot" "woot!") :separator ", ") ;; "Woot, woot, woot!"
split returns a list made up of string parts, delimited by separator.
separator can be a char or any string. It defaults to a space.
Note: Two consecutive separators will be seen as
if there was an empty string between them.
(split "this, is, crazy" ", ") ; ("this" "is" "crazy")
insert returns a original with string inserted at position. If position is not provided, the insertion is performed at the end of original, meaning it is the same as setting position to the length of original
(insert "each day holds " "The infinite possibilities should stagger the mind" :position 27)
;; "The infinite possibilities each day holds should stagger the mind"
repeat returns a string consisting of joining string with itself count number of times, with separator in between
(repeat "clap" 3 :separator " ") ;; "clap clap clap"
chars returns a list with all the characters in a given string
(chars "foo bar") ;; (#\f #\o #\o #\ #\b #\a #\r)
chop returns a list of parts of string, with step elements in each. If step is less than 1, no chop is performed.
(chop "take wrong turns" 5) ;; ("take " "wrong" " turn" "s")
toggle-case returns a string with each character being the opposite case of the original ones.
(toggle-case "oPEN uNMARKED dOORS") ;; "Open Unmarked Doors"
clean removes char from the left and right sides of string, and replaces consecutive sequences of char by a single one.
(clean " foo bar ") ;; "foo bar"
camel-case leaves the case of the first character of string as is. The rest of the words are concatenated and the first letter of each is upcased. Word separation defaults to a space but can be customized by delimiter.
(camel-case "hello worLD") ;; "helloWorld"
kebab-case downcases string and joins every word by an hyphen. Word separation defaults to space but can be customized by delimiter.
(kebab-case "hello worLD") ;; "hello-world"
snake-case leaves the case of the first character of string as is. The rest of the words are lowercased and joined by an underscore. Word separation defaults to space but can be customized by delimiter.
(snake-case "hello worLD") ;; "hello_world"
title-case upcases the first letter of every word in string, and downcases the rest. Word separation removes hyphens by default, but remove-hyphens can be set to nil to change this behaviour.
(title-case "hello-worLD") ;; "Hello World"
If you have any suggestions, bug reports, etc, please fill in an issue describing it. If you have the time and want to contribute, that is even better! Submit some tests too, let's try and keep coverage at 100%.
Here is what I'm thinking might make sense to implement next:
- url-encode / url-decode
- CL specific sanitization / escaping
- String distance measures (Levenshtein, etc.)
MIT