列の分割
文字列の分割を行いたいけど、cl-ppcreパッケージをその(cl-ppcre:split関数の)ためだけに使用したくはなかったので、分割関数を作成した。
;; 第一版: 平易 (defun split (delim seq &aux (len (length delim))) (declare (unmuffle-conditions compiler-note)) (when (zerop len) (return-from split (list seq))) ; これが無いと、delim=空列、の際に無限ループとなる (loop FOR beg = 0 THEN (+ end len) FOR end = (search delim seq :start2 beg) COLLECT (subseq seq beg end) WHILE end)) ;; 第二版: 少し高機能: 開始位置、終端位置、分割個数が指定可能 (defun split (delim seq &key (start 0) end limit) (when (and (numberp limit) (not (plusp limit))) (return-from split '())) (when (zerop len) (return-from split (list seq))) (loop WITH len = (length delim) FOR beg~ = start THEN (+ end~ len) FOR end~ = (if (and limit (zerop (decf limit))) nil (search delim seq :start2 beg~ :end2 end)) COLLECT (subseq seq beg~ (or end~ end)) WHILE end~))
上の関数は、文字列に限らず列一般に対して適用できるという(cl-ppcre:split関数に比べて些細な)利点がある。
> (split "ab" "123abc") --> ("123" "c") > (split "a" '(1 2 3 #\a #\b c)) --> ((1 2 3) (#\b C)) > (split "a" "aaaaaaaaa") ; 区切り文字が連接していると空列となる --> ("" "" "" "" "" "" "" "" "" "") > (split "a" "aaaaaaaaa" :limit 3) ; 要素数を三個までに限定 --> ("" "" "aaaaaaa") > (split "ab" "123abcd" :start 1) ; 開始位置指定: (split "ab" (subseq "123abcd" 1))と等しい --> ("23" "cd")
最近は、LOOPマクロを多用するようになった。
以前は、再帰関数で頑張っていたのに...。