The following function determines the amount of indentation of a string. It returns two values. The first is an effective indentation where tabs are expanded such that their end aligns with 4 spaces steps. The second is just the amount of spaces and tabs before the first non-tab/space character.

roundup is a method that rounds the first argument to next higher multiple of the second argument. The rest is standard CL.

(defun indentation (line)
  (let ((spaces 0))
    (dotimes (index (length line) (values spaces index))
      (case (aref line index)
        (#\Space (incf spaces))
        (#\Tab (setf spaces (roundup (1+ spaces) 4)))
        (otherwise (return (values spaces index)))))))

I don't like having to state the return value twice.


I guess roundup is something like (defun roundup (x y) (* (ceiling x y) y))?

For the reason you stated I'd probably go with loop (or alternatives, iterate comes to mind) instead of the do... family of macros, e.g.:

(defun indentation (line)
    with spaces = 0
    for index below (length line)
    do (case (char line index)
         (#\Space (incf spaces))
         (#\Tab (setf spaces (roundup (1+ spaces) 4)))
         (T (loop-finish)))
    finally (return (values spaces index))))
  • Depending on the choice of input you might want to use char for strings instead of aref.
  • otherwise is pretty long, but of course it's somewhat of a personal choice - t is a bit shorter.
| improve this answer | |
  • 1
    \$\begingroup\$ Your guess is correct. I accept the answer, but will not use it for now. I do not like loop that much. I was not aware of loop-finish. Seeing this used was helpful. \$\endgroup\$ – Philipp Matthias Schäfer Mar 5 '17 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.