Regular Expressions in Lisp

(defpackage :regular-expressions
  (:use :cl :cl-ppcre))

(in-package :regular-expressions)

(defun main ()
  ;; This tests whether a pattern matches a string.
  (format t "~a~%" (scan "p([a-z]+)ch" "peach"))

  ;; Above we used a string pattern directly, but for
  ;; other regexp tasks you'll need to create a scanner object.
  (let ((r (create-scanner "p([a-z]+)ch")))
    
    ;; Many functions are available on these scanner objects. 
    ;; Here's a match test like we saw earlier.
    (format t "~a~%" (scan r "peach"))

    ;; This finds the match for the regexp.
    (format t "~a~%" (scan-to-strings r "peach punch"))

    ;; This also finds the first match but returns the
    ;; start and end indexes for the match instead of the
    ;; matching text.
    (format t "idx: ~a~%" (multiple-value-list (scan r "peach punch")))

    ;; The register-groups-bind macro allows you to capture submatches.
    ;; For example this will return information for both p([a-z]+)ch and ([a-z]+).
    (register-groups-bind (whole submatch) 
        (r "peach punch")
      (format t "~a ~a~%" whole submatch))

    ;; The all-matches function applies to all matches in the input, 
    ;; not just the first. For example to find all matches for a regexp.
    (format t "~a~%" (all-matches-as-strings r "peach punch pinch"))

    ;; Providing a limit as the third argument to these functions will 
    ;; limit the number of matches.
    (format t "~a~%" (all-matches-as-strings r "peach punch pinch" :limit 2))

    ;; Our examples above had string arguments. We can also provide
    ;; vector arguments.
    (format t "~a~%" (scan r (vector #\p #\e #\a #\c #\h)))

    ;; The regex package can also be used to replace
    ;; subsets of strings with other values.
    (format t "~a~%" (regex-replace r "a peach" "<fruit>"))

    ;; The regex-replace-all function allows you to transform matched
    ;; text with a given function.
    (format t "~a~%" (regex-replace-all r "a peach" 
                                        #'(lambda (match &rest registers)
                                            (declare (ignore registers))
                                            (string-upcase match))))))

(main)

This Lisp code demonstrates the use of regular expressions using the CL-PPCRE library, which is a popular regular expression library for Common Lisp. Here’s a breakdown of the translation:

  1. We define a package and use CL-PPCRE for regular expression functionality.
  2. The scan function is used for basic pattern matching.
  3. We create a scanner object with create-scanner for more complex operations.
  4. Various functions like scan-to-strings, all-matches-as-strings, and regex-replace are used to demonstrate different regex operations.
  5. The register-groups-bind macro is used to capture submatches.
  6. We show how to work with both strings and vectors as input.
  7. The regex-replace-all function is used to demonstrate replacing matches with a custom function.

Note that Lisp doesn’t have a direct equivalent to Go’s byte slices, so we use vectors of characters instead.

To run this program, you would need to have a Common Lisp implementation installed (such as SBCL or CCL) and the CL-PPCRE library. You can typically load and run the program using your Lisp REPL or by compiling it to an executable.

This example covers the main concepts of regular expressions in Lisp, demonstrating pattern matching, finding and replacing text, and working with submatches.