Don't even remember.
This commit is contained in:
parent
fe8bba1d3b
commit
722e2f8782
|
@ -0,0 +1,51 @@
|
|||
(in-package :nih)
|
||||
|
||||
;; UNIVERSAL-TIME --> STRING
|
||||
(defun iso-time (universal-time)
|
||||
"Return `universal-time` in ISO 8601 format. :)"
|
||||
|
||||
(multiple-value-bind
|
||||
(second minute hour date month year)
|
||||
(decode-universal-time universal-time)
|
||||
|
||||
(format nil "~A-~A-~A"
|
||||
year
|
||||
(min-string-length month 2 :prefix "0")
|
||||
(min-string-length date 2 :prefix "0"))))
|
||||
|
||||
|
||||
;; NIL --> STRING
|
||||
(defun get-iso-time ()
|
||||
"Return the ISO 8601 time of immediately, right here, right now."
|
||||
|
||||
(iso-time (get-universal-time)))
|
||||
|
||||
|
||||
;; STRING STRING --> INTEGER
|
||||
(defun iso-date-distance (iso-date-a iso-date-b)
|
||||
"Return the number of days between date-a and date-b."
|
||||
|
||||
(let* ((a (mapcar #'read-from-string (nih:char-split "-" iso-date-a)))
|
||||
(year-a (car a)) (month-a (cadr a)) (day-a (caddr a))
|
||||
|
||||
(b (mapcar #'read-from-string (nih:char-split "-" iso-date-b)))
|
||||
(year-b (car b)) (month-b (cadr b)) (day-b (caddr b)))
|
||||
|
||||
(+
|
||||
(* 365 (- year-b year-a))
|
||||
(- (day-number month-b day-b) (day-number month-a day-a)))))
|
||||
|
||||
|
||||
(defvar month-length
|
||||
'(31 28 31 30 31 30 31 31 30 31 30 30))
|
||||
|
||||
|
||||
;; INTEGER [INTEGER] --> INTEGER
|
||||
(defun day-number (month &optional (date 1))
|
||||
"Return the day-number (of a year) of a month/day combo."
|
||||
|
||||
(let ((month-days (reduce #'+ (nih:up-to (- month 2) month-length)))
|
||||
(date-days date))
|
||||
|
||||
(+ month-days date-days)))
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
(in-package :nih)
|
||||
|
||||
;; PATH --> STRING
|
||||
(defun read-file-string (path)
|
||||
"Read all lines from a file into a string."
|
||||
|
||||
(if (file-exists path)
|
||||
(let ((encoding (asdf-encodings:detect-file-encoding path)))
|
||||
|
||||
(with-open-file (fstream path
|
||||
:direction :input
|
||||
:external-format encoding)
|
||||
(line-string
|
||||
(loop
|
||||
:for line = (read-line fstream nil)
|
||||
:while line
|
||||
:collect line))))))
|
||||
|
||||
|
||||
(defun write-file-string (path string &key
|
||||
(if-exists :append)
|
||||
(if-does-not-exist :create))
|
||||
"Write a string to a file."
|
||||
|
||||
(let ((encoding :utf-8))
|
||||
|
||||
(if (file-exists path)
|
||||
(setq encoding (asdf-encodings:detect-file-encoding path)))
|
||||
|
||||
(with-open-file (fstream path
|
||||
:direction :output
|
||||
:external-format encoding
|
||||
:if-exists if-exists
|
||||
:if-does-not-exist if-does-not-exist)
|
||||
(format fstream "~A" string))))
|
|
@ -1,19 +1,19 @@
|
|||
(in-package :nih)
|
||||
|
||||
;; ITEM LIST --> DATA_AFTER_ITEM
|
||||
(defun following (item list)
|
||||
(defun following (item list &key (test #'eq))
|
||||
"Return all items following the first instance of ITEM"
|
||||
|
||||
(cdr (up-from (position item list :test #'equal) list)))
|
||||
(cdr (up-from (position item list :test test) list)))
|
||||
|
||||
|
||||
;; ITEM LIST --> DATA_UP_TO_ITEM
|
||||
(defun preceding (item list)
|
||||
(defun preceding (item list &key (test #'eq))
|
||||
"Return all items preceding the first instance of ITEM"
|
||||
|
||||
(reverse
|
||||
(cdr (reverse
|
||||
(up-to (position item list :test #'equal) list)))))
|
||||
(up-to (position item list :test test) list)))))
|
||||
|
||||
|
||||
;; ----------------------------------------
|
||||
|
@ -93,3 +93,71 @@
|
|||
(setq i (+ 1 i)))
|
||||
|
||||
stack))
|
||||
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
|
||||
;; LIST --> LIST_OF_ODD-NUMBERED_ITEMS
|
||||
(defun odds (list)
|
||||
"Return a list only containing the odd-numbered items of a list."
|
||||
|
||||
(let ((stack '())
|
||||
(i 0))
|
||||
|
||||
(loop
|
||||
:while (< i (length list))
|
||||
:do
|
||||
(if (oddp i)
|
||||
(setq stack (concatenate 'list stack (list (nth i list)))))
|
||||
|
||||
(setq i (+ 1 i)))
|
||||
|
||||
stack))
|
||||
|
||||
|
||||
;; LIST --> LIST_OF_ODD-NUMBERED_ITEMS
|
||||
(defun evens (list)
|
||||
"Return a list only containing the even-numbered items of a list."
|
||||
|
||||
(let ((stack '())
|
||||
(i 0))
|
||||
|
||||
(loop
|
||||
:while (< i (length list))
|
||||
:do
|
||||
(if (evenp i)
|
||||
(setq stack (concatenate 'list stack (list (nth i list)))))
|
||||
|
||||
(setq i (+ 1 i)))
|
||||
|
||||
stack))
|
||||
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
|
||||
|
||||
;; PLIST PLIST --> PLIST
|
||||
(defun property-list-merge (plist-a plist-b)
|
||||
"Merge two property-lists, with plist-a being the canonical one.
|
||||
Useful for when you have defaults (in plist-a) and modifications to
|
||||
them (in plist-b), especially for configs."
|
||||
|
||||
(let* ((keys (evens plist-a))
|
||||
(pairs (length keys))
|
||||
(stack '())
|
||||
(i 0))
|
||||
|
||||
(loop
|
||||
:while (< i pairs)
|
||||
:do
|
||||
(let* ((key (nth i keys))
|
||||
(a-value (getf plist-a key))
|
||||
(b-value (getf plist-b key)))
|
||||
|
||||
(setq stack
|
||||
(append stack
|
||||
(list key (value-or b-value a-value))))
|
||||
(setq i (+ i 1))))
|
||||
stack))
|
||||
|
|
|
@ -49,18 +49,38 @@
|
|||
(defun random-item (list)
|
||||
"Return a random item from a list."
|
||||
|
||||
(nth (random (length list)) list))
|
||||
(if (not list)
|
||||
nil
|
||||
(nth (random (length list)) list)))
|
||||
|
||||
;; INTEGER LIST --> LIST
|
||||
(defun random-items (number list)
|
||||
"Return an amount of random items from a list."
|
||||
|
||||
(if (not list)
|
||||
nil
|
||||
(let ((item (random-item list)))
|
||||
(concatenate 'list
|
||||
(list item)
|
||||
(if (not (eq number 1))
|
||||
(random-items (- number 1) (remove item list)))))))
|
||||
|
||||
;; FILE_PATH --> BOOLEAN
|
||||
(defun file-exists (path)
|
||||
"Return whether or not a file exists."
|
||||
|
||||
(if (ignore-errors (file-author path))
|
||||
'T
|
||||
nil))
|
||||
|
||||
|
||||
;; UNIVERSAL-TIME --> ISO8601-FORMAT_TIME
|
||||
(defun iso-time (universal-time)
|
||||
"Return `universal-time` in ISO 8601 format. :)"
|
||||
;; STREAM --> STRING_OF_ENTIRE_STREAM
|
||||
(defun read-line-entire (stream)
|
||||
(let* ((cur-line (ignore-errors (read-line stream))))
|
||||
|
||||
(multiple-value-bind
|
||||
(second minute hour date month year)
|
||||
(decode-universal-time universal-time)
|
||||
|
||||
(format nil "~A-~A-~A"
|
||||
year
|
||||
(min-string-length month 2 "0")
|
||||
(min-string-length date 2 "0"))))
|
||||
(cond
|
||||
(cur-line
|
||||
(string-combine cur-line
|
||||
(read-line-entire stream)
|
||||
:seperator (format nil "~%")) )
|
||||
('T ""))))
|
||||
|
|
|
@ -16,17 +16,20 @@
|
|||
:regex-get-all
|
||||
:regex-remove
|
||||
:regex-remove-all
|
||||
:regex-split
|
||||
|
||||
:nil-string
|
||||
|
||||
:pad-string
|
||||
:min-string-length
|
||||
:max-string-length
|
||||
|
||||
:getf-string
|
||||
:getf-strings
|
||||
|
||||
:get-colon-values
|
||||
:remove-colon-values
|
||||
:replace-colon-value
|
||||
|
||||
|
||||
;; STRING/WORD
|
||||
|
@ -41,6 +44,8 @@
|
|||
:word-remove-all
|
||||
:word-position
|
||||
:word-positions
|
||||
:word-split
|
||||
:word-length
|
||||
|
||||
:word-car
|
||||
:word-caar :word-cadddrr :word-cadaar :word-cadr :word-caadr
|
||||
|
@ -63,6 +68,8 @@
|
|||
:line-remove-all
|
||||
:line-position
|
||||
:line-positions
|
||||
:line-split
|
||||
:line-length
|
||||
|
||||
:line-car
|
||||
:line-caar :line-cadddrr :line-cadaar :line-cadr :line-caadr
|
||||
|
@ -83,6 +90,8 @@
|
|||
:char-remove-all
|
||||
:char-position
|
||||
:char-positions
|
||||
:char-split
|
||||
:char-length
|
||||
|
||||
:char-car
|
||||
:char-caar :char-cadddrr :char-cadaar :char-cadr :char-caadr
|
||||
|
@ -108,13 +117,37 @@
|
|||
|
||||
:replace-at
|
||||
|
||||
:odds
|
||||
:evens
|
||||
|
||||
:property-list-merge
|
||||
|
||||
|
||||
;; DATE
|
||||
;; =======================
|
||||
:iso-time ;; see (local-time:format-timestring nil timestamp)
|
||||
:get-iso-time
|
||||
;; see (local-time:format-timestring nil (local-time:universal-to-timestamp)
|
||||
:iso-date-distance ;; see #'local-time:timestamp-difference
|
||||
:day-number ;; see #'local-time:format-timestring
|
||||
:week-number ;; see #'local-time:format-timestring
|
||||
|
||||
|
||||
;; FILE
|
||||
;; =======================
|
||||
:read-file-string ;; see #'alexandria:read-file-into-string
|
||||
:write-file-string ;; see #'alexandria:write-string-into-file
|
||||
|
||||
|
||||
;; MISC
|
||||
;; =======================
|
||||
:random-item
|
||||
:random-items
|
||||
:iso-time
|
||||
:list-or-real
|
||||
:value-or
|
||||
:file-exists
|
||||
:read-line-entire
|
||||
:parse-keys))
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,14 @@
|
|||
(nth n (char-list string)))
|
||||
|
||||
|
||||
;; STRING --> INTEGER
|
||||
(defun char-length (string)
|
||||
"Return the length of a string by character."
|
||||
|
||||
(length (char-list string)))
|
||||
|
||||
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
|
||||
|
@ -75,6 +83,14 @@
|
|||
(positions character (char-list string)))
|
||||
|
||||
|
||||
;; CHARACTER STRING --> LIST_OF_STRINGS
|
||||
(defun char-split (character string)
|
||||
"Split a string into a list of strings, at a set character."
|
||||
|
||||
(regex-split (string character)
|
||||
(mapcar #'string (char-list string))))
|
||||
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,14 @@
|
|||
(nth n (line-list string)))
|
||||
|
||||
|
||||
;; STRING --> INTEGER
|
||||
(defun line-length (string)
|
||||
"Return the length of a string in lines."
|
||||
|
||||
(length (line-list string)))
|
||||
|
||||
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
|
||||
|
@ -72,6 +80,13 @@
|
|||
(positions line (line-list string) :test #'equal))
|
||||
|
||||
|
||||
;; QUERY STRING --> LIST_OF_LINES_SANS_MATCHES
|
||||
(defun line-split (query string)
|
||||
"Split a string into a list, seperated by a set line matching a regex query."
|
||||
|
||||
(regex-split query (line-list string) (string #\Newline)))
|
||||
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
|
||||
|
|
|
@ -87,6 +87,26 @@
|
|||
(padding "" string suffix)))))
|
||||
|
||||
|
||||
;; STRING INTEGER --> STRING
|
||||
(defun max-string-length (string length)
|
||||
"Return a string by splitting it into lines, each line being length long."
|
||||
|
||||
(let ((stack "")
|
||||
(i 0))
|
||||
(loop
|
||||
:for char
|
||||
:across string
|
||||
:do
|
||||
(if (eq length i)
|
||||
(progn
|
||||
(setq i 0)
|
||||
(setq stack
|
||||
(nih:string-combine stack (format nil "~%~A" char))))
|
||||
(setq stack
|
||||
(nih:string-combine stack (format nil "~A" char))))
|
||||
(setq i (+ 1 i)))
|
||||
stack))
|
||||
|
||||
|
||||
;; STRING DESIRED_LENGTH [PREFIX] [SUFFIX] --> STRING_OF_DESIRED_LENGTH
|
||||
(defun min-string-length (string target-length
|
||||
|
@ -188,6 +208,35 @@ Example:
|
|||
stack))
|
||||
|
||||
|
||||
;; QUERY LIST_OF_STRINGS --> LIST_SANS_QUERY_MATCHES
|
||||
(defun regex-split (query list &optional (combiner ""))
|
||||
"Split a string into a list, seperated by a set item matching a regex query."
|
||||
|
||||
(let ((stack '(""))
|
||||
(i 0))
|
||||
|
||||
(loop
|
||||
:while (< i (length list))
|
||||
:do
|
||||
(let ((string (nth i list))
|
||||
(last-string (car (reverse stack)))
|
||||
(stack-sans (reverse (cdr (reverse stack)))))
|
||||
|
||||
(cond
|
||||
((ppcre:scan-to-strings query string)
|
||||
(setq stack (concatenate 'list stack (list ""))))
|
||||
('T
|
||||
(setq stack (concatenate 'list stack-sans
|
||||
(list (string-trim combiner
|
||||
(string-combine
|
||||
last-string string
|
||||
:seperator combiner))))))))
|
||||
|
||||
(setq i (+ 1 i)))
|
||||
|
||||
(remove "" stack :test #'equal)))
|
||||
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
|
||||
|
@ -263,8 +312,46 @@ Example:
|
|||
|
||||
|
||||
|
||||
;; STRING COLON_VARIABLE_NAME --> STRING_WITHOUT_COLON_VARIABLE
|
||||
(defun remove-colon-values (string)
|
||||
;; STRING COLON_VARIABLE_NAME --> STRING_WITHOUT_COLON_VARIABLE
|
||||
(defun remove-colon-values (string)
|
||||
"Remove the colon-variable declaration from a string."
|
||||
|
||||
(line-remove-all "^:.*" string))
|
||||
|
||||
|
||||
|
||||
;; STRING SYMBOL STRING --> STRING
|
||||
(defun replace-colon-value (string key-string value)
|
||||
"Replace a colon variable's value."
|
||||
|
||||
(let ((existent
|
||||
(getf (get-colon-values string) (read-from-string key-string))))
|
||||
(if existent
|
||||
(line-replace
|
||||
(line-position
|
||||
(line-get (string-combine "^" key-string " ") string)
|
||||
string)
|
||||
(string-combine key-string value :seperator " ")
|
||||
string)
|
||||
(string-combine :seperator (string #\Newline)
|
||||
string (string-combine key-string " " value)))))
|
||||
|
||||
|
||||
|
||||
|
||||
;; -------------------------------------
|
||||
;; PRIVATE HELPER FUNCTIONS
|
||||
|
||||
|
||||
;; INTEGER STRING STRING --> STRING
|
||||
(defun line-replace (position new-line string)
|
||||
"Replace nth line with a new one in a string."
|
||||
|
||||
(let* ((line-list (nih:line-split (nih:line-nth position string) string))
|
||||
(modified-list
|
||||
(list (car line-list)
|
||||
new-line
|
||||
(nih:value-or (cadr line-list) ""))))
|
||||
|
||||
(reduce (lambda (a b) (nih:string-combine a b :seperator (format nil "~%")))
|
||||
modified-list)))
|
||||
|
|
|
@ -30,6 +30,14 @@
|
|||
(word-string (nth n (word-list string))))
|
||||
|
||||
|
||||
;; STRING --> INTEGER
|
||||
(defun word-length (string)
|
||||
"Return the length of a string by word."
|
||||
|
||||
(length (word-list string)))
|
||||
|
||||
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
|
||||
|
@ -37,7 +45,7 @@
|
|||
(defun word-get (query string)
|
||||
"Return a word in a string that matches a regex query."
|
||||
|
||||
(word-car (word-get-all query string)))
|
||||
(ignore-errors (word-car (word-get-all query string))))
|
||||
|
||||
;; REGEX STRING --> LIST_OF_MATCHING_WORDS
|
||||
(defun word-get-all (query string)
|
||||
|
@ -72,6 +80,12 @@
|
|||
(positions word (word-list string) :test #'equal))
|
||||
|
||||
|
||||
(defun word-split (query string)
|
||||
"Split a string into a list, seperated by a set word matching a regex query."
|
||||
|
||||
(regex-split query (word-list string) " "))
|
||||
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
|
||||
|
|
Reference in New Issue