Plaster

common-lisp
(defun read-link-lines (filename) (with-open-file (stream filename :direction :input :external-format :latin-1) (loop for line = (read-line stream nil nil) while line for pos = (link-position line) when pos collect line))) (defvar *link-lines* (read-link-lines "/home/death/.erc/logs/#lisp.txt")) (defun link-position (string &optional (start 0)) (or (search "http://" string :start2 start) (search "https://" string :start2 start))) (defun extract-links (string) (loop for start = (link-position string) then (link-position string (1+ start)) while start collect (subseq string start (position #\Space string :start start)))) (defvar *links* (mapcan #'extract-links *link-lines*)) (defun extract-domain (link) (let* ((start (+ (search "//" link) 2)) (end (position #\/ link :start start))) (when (> (count #\. link :start start :end end) 1) (let* ((ultimate-dot (position #\. link :start start :end end :from-end t)) (penultimate-dot (position #\. link :start start :end ultimate-dot :from-end t))) (setf start (1+ penultimate-dot)))) (subseq link start end))) (defvar *domains* (mapcar #'extract-domain *links*)) (defun rank (domains &optional (n 20)) (let ((occurrences (make-hash-table :test 'equalp))) (dolist (domain domains) (incf (gethash domain occurrences 0))) (let ((alist (alexandria:hash-table-alist occurrences))) (subseq (sort alist #'> :key #'cdr) 0 n)))) ;; CL-USER> (rank *domains*) ;; (("github.com" . 2818) ("lispworks.com" . 1147) ("tymoon.eu" . 907) ;; ("clozure.com" . 689) ("cliki.net" . 641) ("pastebin.com" . 548) ;; ("common-lisp.net" . 460) ("wikipedia.org" . 299) ("whitequark.org" . 291) ;; ("gitlab.com" . 255) ("metamodular.com" . 253) ("github.io" . 221) ;; ("youtube.com" . 209) ("imgur.com" . 137) ("gigamonkeys.com" . 123) ;; ("dpaste.com" . 106) ("reddit.com" . 98) ("google.com" . 96) ;; ("quicklisp.org" . 91) ("stackoverflow.com" . 89))