(defparameter line-len 87) (setf (documentation 'line-len 'variable) "Characters allowed in one text line") ;; Using subseq; not fancy (defun %limit-len (filepath) (with-output-to-string (out) (with-open-file (in filepath) (loop for line = (read-line in nil nil) while line do (if (< (length line) line-len) (format out "~a~%" line) (let ((seq-start 0)) (loop while (< seq-start (length line)) do (format out "~a~%" (subseq line seq-start (min (length line) (incf seq-start line-len))))))))))) ;; Using split-sequence ;;; However can't handle lines starting with a word longer than one line ;;; Or words longer than two lines generally. (require #:split-sequence) (use-package 'split-sequence) (defun %%limit-len (line) (let ((words (split-sequence #\Space line)) (string "") (counter (let ((count 0)) (lambda (&key incf reset check) (cond (incf (incf count incf)) (reset (setf count 0)) (check (values count)) (t (error ":-("))))))) (loop for word in words do (cond ((and (not (string= string "")) (char= #\newline (char string (1- (length string))))) (setf string (format nil "~a~a" string word)) (funcall counter :incf (length word))) ((and (/= 1 (length word)) (= 1 (- line-len (funcall counter :check t)))) (setf string (format nil "~a~%~a" string word)) (funcall counter :incf (length word))) ((> line-len (+ (funcall counter :check t) (1+ (length word)))) (setf string (format nil "~a ~a" string word)) (funcall counter :incf (1+ (length word)))) ((or (= line-len (+ (funcall counter :check t) (1+ (length word)))) (= line-len (+ (funcall counter :check t) (length word)))) (setf string (format nil "~a ~a~%" string word)) (funcall counter :reset t)) ((/= 1 (length word)) (let ((first-half (subseq word 0 (1- (- line-len (funcall counter :check t))))) (second-half (subseq word (1- (- line-len (funcall counter :check t)))))) (setf string (format nil "~a ~a-~%~a" string first-half second-half)) (funcall counter :reset t) (funcall counter :incf (length second-half)))) (t (error "fell through")))) (values (subseq string 1))))