LISP - Getting Substring
Lisp - String Manipulation and Substrings
Section titled “Lisp - String Manipulation and Substrings”In Common Lisp, a string is a specialized one-dimensional array of characters. Because strings are sequences, many powerful sequence functions can be used to manipulate them. The most fundamental operation for extracting a part of a string is creating a substring.
Extracting Substrings with subseq
Section titled “Extracting Substrings with subseq”The subseq function (short for sub-sequence) is the primary tool for extracting a portion of any sequence, including strings. Its syntax is (subseq sequence start &optional end).
sequence: The string (or other sequence) you want to extract from.start: The 0-based starting index of the substring (inclusive).end: The optional 0-based ending index (exclusive). If omitted, the substring goes to the end of the string.
Example: Basic Substring Extraction
Section titled “Example: Basic Substring Extraction”(defparameter *message* "Welcome to the Lisp world!")
;; Get substring from index 15 to the end(format t "Substring (end): '~a'~%" (subseq *message* 15))
;; Get substring from index 8 to 14(format t "Substring (range): '~a'~%" (subseq *message* 8 14))Output
Section titled “Output”Substring (end): 'Lisp world!'Substring (range): 'to the'Error Handling
Section titled “Error Handling”Calling subseq with invalid indices will signal an error. It’s good practice to validate indices or handle potential errors gracefully, for example, by using handler-case.
Example: Handling Invalid Indices
Section titled “Example: Handling Invalid Indices”(defun safe-subseq (str start &optional end) "A safe wrapper around subseq that returns NIL on error." (handler-case (subseq str start end) ;; In Common Lisp, all errors inherit from the `error` condition. (error (c) (format t "Error while getting substring: ~a~%" c) nil)))
;; --- Usage ---
;; This will fail because the start index is out of bounds(let ((result (safe-subseq "Hello" 10))) (format t "Result of invalid call: ~a~%" result))
;; This will fail because the end index is out of bounds(let ((result (safe-subseq "Hello" 0 100))) (format t "Result of invalid call: ~a~%" result))Output
Section titled “Output”Error while getting substring: The start bounding index, 10, is beyond the end of the sequence, 5.Result of invalid call: NILError while getting substring: The end bounding index, 100, is beyond the end of the sequence, 5.Result of invalid call: NILExplanation
Section titled “Explanation”The handler-case macro attempts to execute its first form. If an error condition is signaled during execution, it catches the condition object c, prints a message, and returns nil instead of crashing the program.
Practical Application: Parsing a Log Entry
Section titled “Practical Application: Parsing a Log Entry”Substrings are essential for parsing structured text. Let’s write a function to parse a log entry like "[INFO] 2023-10-27: User logged in." into its components.
(defun parse-log-entry (log-line) "Parses a log entry and returns its components as a list." (let* ((level-end (position #] log-line)) (date-start (+ level-end 2)) (date-end (+ date-start 10)) (msg-start (+ date-end 2))) (list :level (subseq log-line 1 level-end) :date (subseq log-line date-start date-end) :message (subseq log-line msg-start))))
;; --- Usage ---(defparameter *log1* "[INFO] 2023-10-27: User logged in.")(defparameter *log2* "[ERROR] 2023-10-28: Database connection failed.")
(print (parse-log-entry *log1*))(print (parse-log-entry *log2*))Output
Section titled “Output”(:LEVEL "INFO" :DATE "2023-10-27" :MESSAGE "User logged in.")(:LEVEL "ERROR" :DATE "2023-10-28" :MESSAGE "Database connection failed.")Other Useful String Functions
Section titled “Other Useful String Functions”Beyond subseq, the Lisp standard library includes many other helpful functions for string manipulation:
- Searching:
(search "needle" "haystack")finds the starting position of a substring. - Concatenation:
(concatenate 'string "Hello, " "world!")joins multiple strings together. - Trimming:
(string-trim '(#\Space #\Tab) " some text ")removes whitespace from the ends. - Case Conversion:
string-upcase,string-downcase, andstring-capitalizechange the case of a string.