-
Notifications
You must be signed in to change notification settings - Fork 3
/
util.lisp
63 lines (56 loc) · 2.09 KB
/
util.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
;;
;; util.lisp
;;
;; Various utilities
;;
(in-package :cl-phonetic)
(defmacro string-extract (str re names-list &rest body)
"Basically, `multiple-value-bind', but for CL-PPCRE capture groups.
Scan STR with RE, binding NAMES-LIST to the resulting matches, and
finally, evaluate BODY. Behavior is undefined if RE does not match
STR, or if the number of capture groups is not equal to the number of
names in NAMES-LIST."
(let ((whole-sym (gensym))
(matches-sym (gensym)))
`(multiple-value-bind (,whole-sym ,matches-sym)
(ppcre:scan-to-strings ,re ,str)
(declare (ignore ,whole-sym))
(destructuring-bind ,names-list (coerce ,matches-sym 'list)
,@body))))
(defun insert (sequence element idx)
"Insert an element ELEMENT into SEQUENCE at index IDX."
(append (subseq sequence 0 idx)
(list element)
(subseq sequence idx)))
(defun seqjoin (result-type sequence delimiter)
"Insert DELIMITER between every element in SEQUENCE."
(let
((alternator 1))
(flet
((merge-closure (elt-left elt-right)
"Yields an infinite series of nil, t, nil, t, ..."
(declare (ignorable elt-left elt-right))
(> (setq alternator (* alternator -1)) 0)))
(merge result-type
sequence
(make-list (- (length sequence) 1) :initial-element delimiter)
#'merge-closure))))
(defun glue-strings (&rest strings-or-lists)
"Combine a bunch of strings, or lists of strings, into one final
string."
(apply #'concatenate 'string (flatten strings-or-lists)))
(defun join-strings (delimiter &rest strings-or-lists)
"GLUE-STRINGS, but with a delimiter between joins."
(glue-strings (seqjoin 'list (flatten strings-or-lists) delimiter)))
(defun nth-position-if (n predicate sequence)
"Get the position of the nth item to meet predicate, or nil."
(let
((counter 0))
(loop for item in sequence
and position from 0 do
(progn
(if (funcall predicate item)
(incf counter))
(when (> counter n)
(return-from nth-position-if position))))
nil))