diff options
Diffstat (limited to 'lisp/ldg-commodities.el')
-rw-r--r-- | lisp/ldg-commodities.el | 156 |
1 files changed, 89 insertions, 67 deletions
diff --git a/lisp/ldg-commodities.el b/lisp/ldg-commodities.el index 031bddeb..da551965 100644 --- a/lisp/ldg-commodities.el +++ b/lisp/ldg-commodities.el @@ -36,50 +36,47 @@ (defun ledger-split-commodity-string (str) "Split a commoditized string, STR, into two parts. Returns a list with (value commodity)." - (if (> (length str) 0) - (let ((number-regex (if (assoc "decimal-comma" ledger-environment-alist) - ledger-amount-decimal-comma-regex - ledger-amount-decimal-period-regex))) - (with-temp-buffer - (insert str) - (goto-char (point-min)) - (cond - ((re-search-forward "\"\\(.*\\)\"" nil t) ; look for quoted commodities - (let ((com (delete-and-extract-region - (match-beginning 1) - (match-end 1)))) - (if (re-search-forward number-regex nil t) - (list - (string-to-number - (ledger-commodity-string-number-decimalize - (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user)) - com)))) - ((re-search-forward number-regex nil t) - ;; found a number in the current locale, return it in - ;; the car. Anything left over is annotation, - ;; the first thing should be the commodity, separated - ;; by whitespace, return it in the cdr. I can't think of any - ;; counterexamples - (list - (string-to-number - (ledger-commodity-string-number-decimalize - (delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user)) - (nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max)))))) - ((re-search-forward "0" nil t) - ;; couldn't find a decimal number, look for a single 0, - ;; indicating account with zero balance - (list 0 ledger-reconcile-default-commodity))))) - ;; nothing found, return 0 - (list 0 ledger-reconcile-default-commodity))) + (let ((number-regex (if (assoc "decimal-comma" ledger-environment-alist) + ledger-amount-decimal-comma-regex + ledger-amount-decimal-period-regex))) + (if (> (length str) 0) + (with-temp-buffer + (insert str) + (goto-char (point-min)) + (cond + ((re-search-forward "\"\\(.*\\)\"" nil t) ; look for quoted commodities + (let ((com (delete-and-extract-region + (match-beginning 1) + (match-end 1)))) + (if (re-search-forward + number-regex nil t) + (list + (ledger-string-to-number + (delete-and-extract-region (match-beginning 0) (match-end 0))) + com)))) + ((re-search-forward number-regex nil t) + ;; found a number in the current locale, return it in the + ;; car. Anything left over is annotation, the first + ;; thing should be the commodity, separated by + ;; whitespace, return it in the cdr. I can't think of + ;; any counterexamples + (list + (ledger-string-to-number + (delete-and-extract-region (match-beginning 0) (match-end 0))) + (nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max)))))) + ((re-search-forward "0" nil t) + ;; couldn't find a decimal number, look for a single 0, + ;; indicating account with zero balance + (list 0 ledger-reconcile-default-commodity)))) + ;; nothing found, return 0 + (list 0 ledger-reconcile-default-commodity)))) (defun ledger-string-balance-to-commoditized-amount (str) "Return a commoditized amount (val, 'comm') from STR." - (let ((fields (split-string str "[\n\r]"))) ; break any balances - ; with multi commodities - ; into a list - (mapcar #'(lambda (str) - (ledger-split-commodity-string str)) - fields))) + ; break any balances with multi commodities into a list + (mapcar #'(lambda (st) + (ledger-split-commodity-string st)) + (split-string str "[\n\r]"))) (defun -commodity (c1 c2) "Subtract C2 from C1, ensuring their commodities match." @@ -93,27 +90,53 @@ Returns a list with (value commodity)." (list (+ (car c1) (car c2)) (cadr c1)) (error "Can't add different commodities, %S to %S" c1 c2))) -(defun ledger-commodity-string-number-decimalize (number-string direction) - "Take NUMBER-STRING and ensure proper decimalization for use by string-to-number and number-to-string. - -DIRECTION can be :to-user or :from-user. All math calculations -are done with decimal-period, some users may prefer decimal-comma -which must be translated both directions." - (let ((val number-string)) - (if (assoc "decimal-comma" ledger-environment-alist) - (cond ((eq direction :from-user) - ;; change string to decimal-period - (while (string-match "," val) - (setq val (replace-match "." nil nil val)))) ;; switch to period separator - ((eq direction :to-user) - ;; change to decimal-comma - (while (string-match "\\." val) - (setq val (replace-match "," nil nil val)))) ;; gets rid of periods - (t - (error "ledger-commodity-string-number-decimalize: direction not properly specified %S" direction))) - (while (string-match "," val) - (setq val (replace-match "" nil nil val)))) - val)) +(defun ledger-strip (str char) + (let (new-str ) + + (dolist (ch (append str nil)) + (unless (= ch char) + (setq new-str (append new-str (list ch))))) + (concat new-str))) + +(defun ledger-string-to-number (str &optional decimal-comma) + "improve builtin string-to-number by handling internationalization, and return nil of number can't be parsed" + (let ((nstr (if (or decimal-comma + (assoc "decimal-comma" ledger-environment-alist)) + (ledger-strip str ?.) + (ledger-strip str ?,)))) + (while (string-match "," nstr) + (setq nstr (replace-match "." nil nil nstr))) + (string-to-number nstr))) + +(defun ledger-number-to-string (n &optional decimal-comma) + (let ((str (number-to-string n))) + (if (or decimal-comma + (assoc "decimal-comma" ledger-environment-alist)) + (while (string-match "\\." str) + (setq str (replace-match "," nil nil str))) + str))) + +;; (defun ledger-commodity-string-number-decimalize (number-string direction) +;; "Take NUMBER-STRING and ensure proper decimalization for use by string-to-number and number-to-string. + +;; DIRECTION can be :to-user or :from-user. All math calculations +;; are done with decimal-period, some users may prefer decimal-comma +;; which must be translated both directions." +;; (let ((val number-string)) +;; (if (assoc "decimal-comma" ledger-environment-alist) +;; (cond ((eq direction :from-user) +;; ;; change string to decimal-period +;; (while (string-match "," val) +;; (setq val (replace-match "." nil nil val)))) ;; switch to period separator +;; ((eq direction :to-user) +;; ;; change to decimal-comma +;; (while (string-match "\\." val) +;; (setq val (replace-match "," nil nil val)))) ;; gets rid of periods +;; (t +;; (error "ledger-commodity-string-number-decimalize: direction not properly specified %S" direction))) +;; (while (string-match "," val) +;; (setq val (replace-match "" nil nil val)))) +;; val)) @@ -121,12 +144,11 @@ which must be translated both directions." "Return string representing C1. Single character commodities are placed ahead of the value, longer ones are after the value." -(let ((val (ledger-commodity-string-number-decimalize - (number-to-string (car c1)) :to-user)) - (commodity (cadr c1))) + (let ((str (ledger-number-to-string (car c1))) + (commodity (cadr c1))) (if (> (length commodity) 1) - (concat val " " commodity) - (concat commodity " " val)))) + (concat str " " commodity) + (concat commodity " " str)))) (defun ledger-read-commodity-string (prompt) (let ((str (read-from-minibuffer |