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)
|
(in-package :nih)
|
||||||
|
|
||||||
;; ITEM LIST --> DATA_AFTER_ITEM
|
;; 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"
|
"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
|
;; 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"
|
"Return all items preceding the first instance of ITEM"
|
||||||
|
|
||||||
(reverse
|
(reverse
|
||||||
(cdr (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)))
|
(setq i (+ 1 i)))
|
||||||
|
|
||||||
stack))
|
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)
|
(defun random-item (list)
|
||||||
"Return a random item from a 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
|
;; STREAM --> STRING_OF_ENTIRE_STREAM
|
||||||
(defun iso-time (universal-time)
|
(defun read-line-entire (stream)
|
||||||
"Return `universal-time` in ISO 8601 format. :)"
|
(let* ((cur-line (ignore-errors (read-line stream))))
|
||||||
|
|
||||||
(multiple-value-bind
|
(cond
|
||||||
(second minute hour date month year)
|
(cur-line
|
||||||
(decode-universal-time universal-time)
|
(string-combine cur-line
|
||||||
|
(read-line-entire stream)
|
||||||
(format nil "~A-~A-~A"
|
:seperator (format nil "~%")) )
|
||||||
year
|
('T ""))))
|
||||||
(min-string-length month 2 "0")
|
|
||||||
(min-string-length date 2 "0"))))
|
|
||||||
|
|
|
@ -16,17 +16,20 @@
|
||||||
:regex-get-all
|
:regex-get-all
|
||||||
:regex-remove
|
:regex-remove
|
||||||
:regex-remove-all
|
:regex-remove-all
|
||||||
|
:regex-split
|
||||||
|
|
||||||
:nil-string
|
:nil-string
|
||||||
|
|
||||||
:pad-string
|
:pad-string
|
||||||
:min-string-length
|
:min-string-length
|
||||||
|
:max-string-length
|
||||||
|
|
||||||
:getf-string
|
:getf-string
|
||||||
:getf-strings
|
:getf-strings
|
||||||
|
|
||||||
:get-colon-values
|
:get-colon-values
|
||||||
:remove-colon-values
|
:remove-colon-values
|
||||||
|
:replace-colon-value
|
||||||
|
|
||||||
|
|
||||||
;; STRING/WORD
|
;; STRING/WORD
|
||||||
|
@ -41,6 +44,8 @@
|
||||||
:word-remove-all
|
:word-remove-all
|
||||||
:word-position
|
:word-position
|
||||||
:word-positions
|
:word-positions
|
||||||
|
:word-split
|
||||||
|
:word-length
|
||||||
|
|
||||||
:word-car
|
:word-car
|
||||||
:word-caar :word-cadddrr :word-cadaar :word-cadr :word-caadr
|
:word-caar :word-cadddrr :word-cadaar :word-cadr :word-caadr
|
||||||
|
@ -63,6 +68,8 @@
|
||||||
:line-remove-all
|
:line-remove-all
|
||||||
:line-position
|
:line-position
|
||||||
:line-positions
|
:line-positions
|
||||||
|
:line-split
|
||||||
|
:line-length
|
||||||
|
|
||||||
:line-car
|
:line-car
|
||||||
:line-caar :line-cadddrr :line-cadaar :line-cadr :line-caadr
|
:line-caar :line-cadddrr :line-cadaar :line-cadr :line-caadr
|
||||||
|
@ -83,6 +90,8 @@
|
||||||
:char-remove-all
|
:char-remove-all
|
||||||
:char-position
|
:char-position
|
||||||
:char-positions
|
:char-positions
|
||||||
|
:char-split
|
||||||
|
:char-length
|
||||||
|
|
||||||
:char-car
|
:char-car
|
||||||
:char-caar :char-cadddrr :char-cadaar :char-cadr :char-caadr
|
:char-caar :char-cadddrr :char-cadaar :char-cadr :char-caadr
|
||||||
|
@ -108,13 +117,37 @@
|
||||||
|
|
||||||
:replace-at
|
: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
|
;; MISC
|
||||||
;; =======================
|
;; =======================
|
||||||
:random-item
|
:random-item
|
||||||
|
:random-items
|
||||||
:iso-time
|
:iso-time
|
||||||
:list-or-real
|
:list-or-real
|
||||||
:value-or
|
:value-or
|
||||||
|
:file-exists
|
||||||
|
:read-line-entire
|
||||||
:parse-keys))
|
:parse-keys))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,14 @@
|
||||||
(nth n (char-list string)))
|
(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)))
|
(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)))
|
(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))
|
(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)))))
|
(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
|
;; STRING DESIRED_LENGTH [PREFIX] [SUFFIX] --> STRING_OF_DESIRED_LENGTH
|
||||||
(defun min-string-length (string target-length
|
(defun min-string-length (string target-length
|
||||||
|
@ -188,6 +208,35 @@ Example:
|
||||||
stack))
|
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)))
|
||||||
|
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@ -268,3 +317,41 @@ Example:
|
||||||
"Remove the colon-variable declaration from a string."
|
"Remove the colon-variable declaration from a string."
|
||||||
|
|
||||||
(line-remove-all "^:.*" 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))))
|
(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)
|
(defun word-get (query string)
|
||||||
"Return a word in a string that matches a regex query."
|
"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
|
;; REGEX STRING --> LIST_OF_MATCHING_WORDS
|
||||||
(defun word-get-all (query string)
|
(defun word-get-all (query string)
|
||||||
|
@ -72,6 +80,12 @@
|
||||||
(positions word (word-list string) :test #'equal))
|
(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