;;;; -*- mode:lisp;coding:utf-8 -*-

;; "SPLIT-STRING"
;; "STRING-MATCH" "MATCH-STRING" "MATCH-BEGINNING" "MATCH-END"
;; "REGEXP-MATCh-ANY" "REGEXP-COMPILE" "REGEXP-QUOTE-EXTENDED"


(defun split-string (string regexp)
  #-(or use-ppcre (and clisp use-regexp))
  (error "Please implement ~S (perhaps push :use-ppcre on *feature*)." 'split-string)
  #+(and clisp use-regexp) (regexp:regexp-split regexp string)
  #+use-ppcre (cl-ppcre:split regexp string))


(defvar *string-match-results* '())

(defun string-match (regexp string)
  #-(or use-ppcre (and clisp use-regexp))
  (error "Please implement ~S (perhaps push :use-ppcre on *feature*)." 'split-match)
  #+(and clisp use-regexp)
  (setf *string-match-results*
        (let ((results  (if (stringp regexp)
                            (multiple-value-list
                             (regexp:match regexp string :extended t :ignore-case nil :newline t :nosub nil))
                            (regexp:regexp-exec (cdr regexp) string :return-type 'list))))
          (if (equal '(nil) results)
              nil
              results)))
  #+use-ppcre
  (setf *string-match-results*
        (let ((results (multiple-value-list
                        (if (stringp regexp)
                            (cl-ppcre:scan regexp       string)
                            (cl-ppcre:scan (cdr regexp) string)))))
          (if (equal '(nil) results)
              nil
              (destructuring-bind (as ae ss es) results
                  (list as ae
                        (concatenate 'vector (vector as) ss)
                        (concatenate 'vector (vector ae) es)))))))

(defun match-string (index string)
  #-(or use-ppcre (and clisp use-regexp))
  (error "Please implement ~S (perhaps push :use-ppcre on *feature*)." 'match-string)
  #+(and clisp use-regexp)
  (let ((m (elt *string-match-results* index)))
    (when m (regexp:match-string string m)))
  #+use-ppcre
  (let ((start (ignore-errors (aref (elt *string-match-results* 2) index)))
        (end   (ignore-errors (aref (elt *string-match-results* 3) index))))
    (when (and start end)
      (subseq string start end))))

(defun match-beginning (index)
  #-(or use-ppcre (and clisp use-regexp))
  (error "Please implement ~S (perhaps push :use-ppcre on *feature*)." 'match-beginning)
  #+(and clisp use-regexp)
  (let ((m (elt *string-match-results* index)))
    (when m (regexp:match-start m)))
  #+use-ppcre
  (ignore-errors (aref (elt *string-match-results* 2) index)))

(defun match-end (index)
  #-(or use-ppcre (and clisp use-regexp))
  (error "Please implement ~S (perhaps push :use-ppcre on *feature*)." 'match-end)
  #+(and clisp use-regexp)
  (let ((m (elt *string-match-results* index)))
    (when m (regexp:match-end m)))
  #+use-ppcre
  (ignore-errors (aref (elt *string-match-results* 3) index)))

(defun regexp-match-any (groupsp)
  #- (or use-ppcre (and clisp use-regexp))
  (error "Please implement ~S (perhaps push :use-ppcre on *feature*)." 'regexp-match-any)
  #+(and clisp use-regexp) (if groupsp "(.*)" ".*")
  #+use-ppcre              (if groupsp "(.*)" ".*"))

(defun regexp-compile (regexp)
  #- (or use-ppcre (and clisp use-regexp))
  (error "Please implement ~S (perhaps push :use-ppcre on *feature*)." 'regexp-compile)
  #+(and clisp use-regexp) (regexp:regexp-compile regexp
                                                  :extended t
                                                  :ignore-case nil
                                                  :newline t
                                                  :nosub nil)
  #+use-ppcre (cl-ppcre:create-scanner regexp
                                       :case-insensitive-mode nil
                                       :multi-line-mode nil
                                       :extended-mode nil
                                       :destructive nil))

(defun regexp-quote-extended (string)
  ;; #+clisp regexp:regexp-quote doesn't quote extended regexps...
  ;;        (regexp:regexp-quote "(abc .*" t) --> "(abc \\.\\*"  instead of "\\(abc \\.\\*"
  #-use-ppcre
  (let* ((special-characters "^.[$()|*+?{\\")
         (increase (count-if (lambda (ch) (find ch special-characters)) string)))
     (if (zerop increase)
         string
         (let ((result (make-array (+ (length string) increase)
                                    :element-type 'character)))
           (loop
              :with i = -1
              :for ch :across string
              :do (if (find ch special-characters)
                      (setf (aref result (incf i)) #\\
                            (aref result (incf i)) ch)
                      (setf (aref result (incf i)) ch)))
           result)))
  #+use-ppcre
  (cl-ppcre:quote-meta-chars string))

ViewGit