Plaster

common-lisp
(defmacro parse-using-digits-template (template string &key (extract 'parse-integer) (start 0) (at-end nil)) "Extract numbers from a string matching the supplied template." (once-only (string) (cond ((and at-end (not (eql 0 start))) (error "Don't know what to do when both at-end true and start nonzero are supplied.")) (at-end (setf start `(- (length ,string) ,(length template))))) (once-only (start) `(progn (when (/= (length ,string) (+ ,start ,(length template))) (error "String length doesn't match template's.")) (when (or ,@(loop for i from 0 for c across template when (and (not (digit-char-p c)) (char/= c #\?)) collect `(char/= ,c (char ,string (+ ,start ,i))))) (error "String doesn't match template.")) (values ,@(loop for i below 10 for d = (digit-char i) for s = (position d template) when s collect (let ((e (or (position d template :start s :test-not #'char=) (length template)))) `(,extract ,string :start (+ ,start ,s) :end (+ ,start ,e)))))))))