opening it up with Common Lisp

Favorite weblogs

Lisp Related

Bill Clementson

Finding Lisp

Lemonodor

Lispmeister.com

Planet Lisp

Politics

Orcinus

Talking Points Memo

This Modern World

Working for Change

Other home

Polliblog

Recent Readings

Book review: Darwinia
Reviewed: Friday, August 11, 2006

Summer reading: Spin
Reviewed: Saturday, August 5, 2006

Runner
Reviewed: Tuesday, July 18, 2006

the Omnivoire's Delimma
Reviewed: Wednesday, July 12, 2006

the Golem's Eye
Reviewed: Wednesday, May 31, 2006





tinderbox
 width=

Simple file parsing in Common Lisp
Friday, September 30, 2005

Here's some code I wrote to read a file of transactions from my bank and convert it into a nice list. The data looks like:

09/29/05
Checking
EFT PAYMENT Comcast FSBlink Chan
$-58.26

09/27/05
Checking
Check 564
564
$-10.00

I.e., each transaction is spread out over four (or five) lines. My code reads the lines, munges transactions together and then post-processes then into an easier to read format.

The Lisp code is readable but a bit verbose... I know that the munging step could be done with a regular expression but, sadly, I'm not expert enough to be able to whip one up that would work (especially one that would deal with either four or five lines for each transaction).

Oh, there's also a bunch of personal utility functions in the code (e-mail me if you're that interested!). This includes: collect-elements, map-lines-in-file, string-trim, bind, time-month and time-date.


(defun parse-transactions ()
  (collect-elements
   (let ((buffer nil)
         (result nil))
     (flet ((parse-buffer ()
              (when buffer
                (push (nreverse buffer) result)
                (setf buffer nil)))
            (add-line (line)
              (push line buffer)))
       (map-lines-in-file 
        (lambda (line) 
          (if (zerop (size (string-trim " " line)))
            (parse-buffer)
            (add-line line)))
        "p2dis:data;transactions")
       (parse-buffer)
       result))
   :transform
   (lambda (transaction)
     (bind (((date nil comment amount-or-check &optional amount) transaction)
            (date-and-time (apply #'encode-universal-time
                                  (multiple-value-list 
                                   (parse-date-and-time-string date))))
            (is-check? (and amount 
                            (string-equal comment "check " :end1 6)))
            (dollars (parse-integer 
                      (remove #\, (if is-check? amount amount-or-check) 
                              :test #'char-equal)
                      :start 1 :junk-allowed t))
            (kind nil))
       (flet ((fixup (find remove the-kind &optional replace)
                (when (string-equal comment find :end1 (min (size find) (size comment)))
                  (setf kind the-kind)
                  (when remove
                    (setf comment 
                          (subseq comment (min (size remove) (size comment)))))
                  (when replace
                    (setf comment replace))
                  (values t))))
         (or (fixup "EFT" "EFT PAYMENT " "EFT")
             (fixup "POS" "POS WITHDRAWAL (DBT)" "POS")
             (fixup "ATM" nil "ATM" "Withdrawal")
             (fixup "External" "External Withdrawal" "EFT")
             (fixup "Deposit" nil "dpt")
             (fixup "Insufficient" "Insufficient Funds/Ovdft. Fee " "---")
             (fixup "Overdraft Protection" nil "opd")
             (and is-check? (setf kind "CHK")))
         (list kind comment dollars (time-month date-and-time) (time-date date-and-time)))))))

|

Home | About | Quotes | Recent | Archives

Copyright -- Gary Warren King, 2004 - 2006