LISP - String Trimmimg
Modern Lisp: String Trimming
Section titled “Modern Lisp: String Trimming”In Common Lisp, removing unwanted characters from the beginning or end of a string—a process known as trimming—is a common and straightforward task. The language provides a set of powerful, built-in functions designed for this purpose. This updated tutorial explores these functions, their modern usage, and best practices.
Standard String Trimming Functions
Section titled “Standard String Trimming Functions”The core of string trimming in Common Lisp revolves around three primary functions. They all work by comparing characters in the string against a character bag—a sequence containing the characters to be removed.
| Function | Description |
|---|---|
string-trim | Takes a character bag and a string. It returns a new string with all characters from the bag removed from both the beginning and the end. |
string-left-trim | Similar to string-trim, but only removes characters from the beginning (left side) of the string. |
string-right-trim | Similar to string-trim, but only removes characters from the end (right side) of the string. |
What is a Character Bag?
Section titled “What is a Character Bag?”The first argument to these functions is a sequence of characters, which we call a ‘character bag’. It is not a substring to be matched. Instead, any character present in the bag will be trimmed from the target string. The order of characters in the bag does not matter.
For example, if the character bag is "ab ", the functions will trim any ‘a’, ‘b’, or space character from the ends of the string.
Example: Using Built-in Trimming Functions
Section titled “Example: Using Built-in Trimming Functions”Let’s see these functions in action. The following code demonstrates how to trim whitespace and other characters from a string. We use format for output, which is a highly flexible and idiomatic way to print text in Lisp.
(defun run-trimming-examples () "Demonstrates the standard string trimming functions." (let ((my-string " a big hello from tutorials point ") (whitespace-bag '(#\Space #\Tab #\Newline)))
(format t "Original: '~a'~%~%" my-string)
;; Trim whitespace from both ends (format t "string-trim: '~a'~%" (string-trim whitespace-bag my-string))
;; Trim whitespace from the left only (format t "string-left-trim: '~a'~%" (string-left-trim whitespace-bag my-string))
;; Trim whitespace from the right only (format t "string-right-trim: '~a'~%" (string-right-trim whitespace-bag my-string))
;; Example with a different character bag (let ((another-string "...!!hello world!!...") (punctuation-bag ".!")) (format t "~%Trimming punctuation: '~a'~%" (string-trim punctuation-bag another-string)))))
;; Run the examples(run-trimming-examples)Output
Section titled “Output”Original: ' a big hello from tutorials point '
string-trim: 'a big hello from tutorials point'string-left-trim: 'a big hello from tutorials point 'string-right-trim: ' a big hello from tutorials point'
Trimming punctuation: 'hello world'Advanced Topic: A Custom Trim Function
Section titled “Advanced Topic: A Custom Trim Function”While the built-in functions are usually sufficient, you might occasionally need to trim based on a condition rather than a fixed set of characters. For example, you might want to trim all digits from a string. This requires a custom function that uses predicates.
The following is a well-structured custom trim-if function. Notice the use of position-if-not to find the first character that should not be trimmed.
(defun trim-if (predicate string) "Trims characters from both ends of STRING for which PREDICATE returns true. Example: (trim-if #'digit-char-p \"123hello456\") => \"hello\"" (let* ((start (position-if-not predicate string)) (end (position-if-not predicate string :from-end t))) (if start (subseq string start (and end (1+ end))) "")))
;; --- Example Usage ---
;; Trim all characters that are digits(format t "Custom trim (digits): '~a'~%" (trim-if #'digit-char-p "123abc456"))
;; Trim all characters that are not letters(format t "Custom trim (non-letters): '~a'~%" (trim-if (lambda (c) (not (alpha-char-p c))) "--hello world!--"))Output
Section titled “Output”Custom trim (digits): 'abc'Custom trim (non-letters): 'hello world'Best Practices and Common Pitfalls
Section titled “Best Practices and Common Pitfalls”- Prefer Built-ins: Always use the standard
string-trim,string-left-trim, andstring-right-trimwhen possible. They are highly optimized and part of the standard, making your code portable and readable. - Character Bag vs. Substring: A common mistake is to think
(string-trim "abc" "abcdef")will remove the prefix “abc”. It will not. It removes any ‘a’, ‘b’, or ‘c’ characters from the ends. In this case, the result is"def". - Performance: For performance-critical code, remember that these functions create a new string. Trimming in a tight loop can lead to memory allocation overhead. If performance is an issue, consider alternative data processing strategies.