summaryrefslogtreecommitdiff
path: root/lisp/ldg-commodities.el
diff options
context:
space:
mode:
authorCraig Earls <enderw88@gmail.com>2013-04-13 21:55:06 -0700
committerCraig Earls <enderw88@gmail.com>2013-04-13 21:55:06 -0700
commit971bcf22f4282ef9813a9fe9bb4966e03d50c48c (patch)
treee3175acf97eaa5f52e85d41f85464a3edfce079b /lisp/ldg-commodities.el
parentb2c88149cb09387023b28f5af0a9ad1640a0c9c3 (diff)
downloadfork-ledger-971bcf22f4282ef9813a9fe9bb4966e03d50c48c.tar.gz
fork-ledger-971bcf22f4282ef9813a9fe9bb4966e03d50c48c.tar.bz2
fork-ledger-971bcf22f4282ef9813a9fe9bb4966e03d50c48c.zip
Bug 951, handle thousand separators.
Rewrote handling for decimal comma to be much simpler. Why can't I see the simple way first?
Diffstat (limited to 'lisp/ldg-commodities.el')
-rw-r--r--lisp/ldg-commodities.el156
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