Bug 951, handle thousand separators.
Rewrote handling for decimal comma to be much simpler. Why can't I see the simple way first?
This commit is contained in:
parent
b2c88149cb
commit
971bcf22f4
5 changed files with 290 additions and 268 deletions
|
|
@ -36,10 +36,10 @@
|
||||||
(defun ledger-split-commodity-string (str)
|
(defun ledger-split-commodity-string (str)
|
||||||
"Split a commoditized string, STR, into two parts.
|
"Split a commoditized string, STR, into two parts.
|
||||||
Returns a list with (value commodity)."
|
Returns a list with (value commodity)."
|
||||||
(if (> (length str) 0)
|
|
||||||
(let ((number-regex (if (assoc "decimal-comma" ledger-environment-alist)
|
(let ((number-regex (if (assoc "decimal-comma" ledger-environment-alist)
|
||||||
ledger-amount-decimal-comma-regex
|
ledger-amount-decimal-comma-regex
|
||||||
ledger-amount-decimal-period-regex)))
|
ledger-amount-decimal-period-regex)))
|
||||||
|
(if (> (length str) 0)
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert str)
|
(insert str)
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
|
|
@ -48,38 +48,35 @@ Returns a list with (value commodity)."
|
||||||
(let ((com (delete-and-extract-region
|
(let ((com (delete-and-extract-region
|
||||||
(match-beginning 1)
|
(match-beginning 1)
|
||||||
(match-end 1))))
|
(match-end 1))))
|
||||||
(if (re-search-forward number-regex nil t)
|
(if (re-search-forward
|
||||||
|
number-regex nil t)
|
||||||
(list
|
(list
|
||||||
(string-to-number
|
(ledger-string-to-number
|
||||||
(ledger-commodity-string-number-decimalize
|
(delete-and-extract-region (match-beginning 0) (match-end 0)))
|
||||||
(delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))
|
|
||||||
com))))
|
com))))
|
||||||
((re-search-forward number-regex nil t)
|
((re-search-forward number-regex nil t)
|
||||||
;; found a number in the current locale, return it in
|
;; found a number in the current locale, return it in the
|
||||||
;; the car. Anything left over is annotation,
|
;; car. Anything left over is annotation, the first
|
||||||
;; the first thing should be the commodity, separated
|
;; thing should be the commodity, separated by
|
||||||
;; by whitespace, return it in the cdr. I can't think of any
|
;; whitespace, return it in the cdr. I can't think of
|
||||||
;; counterexamples
|
;; any counterexamples
|
||||||
(list
|
(list
|
||||||
(string-to-number
|
(ledger-string-to-number
|
||||||
(ledger-commodity-string-number-decimalize
|
(delete-and-extract-region (match-beginning 0) (match-end 0)))
|
||||||
(delete-and-extract-region (match-beginning 0) (match-end 0)) :from-user))
|
|
||||||
(nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max))))))
|
(nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max))))))
|
||||||
((re-search-forward "0" nil t)
|
((re-search-forward "0" nil t)
|
||||||
;; couldn't find a decimal number, look for a single 0,
|
;; couldn't find a decimal number, look for a single 0,
|
||||||
;; indicating account with zero balance
|
;; indicating account with zero balance
|
||||||
(list 0 ledger-reconcile-default-commodity)))))
|
(list 0 ledger-reconcile-default-commodity))))
|
||||||
;; nothing found, return 0
|
;; nothing found, return 0
|
||||||
(list 0 ledger-reconcile-default-commodity)))
|
(list 0 ledger-reconcile-default-commodity))))
|
||||||
|
|
||||||
(defun ledger-string-balance-to-commoditized-amount (str)
|
(defun ledger-string-balance-to-commoditized-amount (str)
|
||||||
"Return a commoditized amount (val, 'comm') from STR."
|
"Return a commoditized amount (val, 'comm') from STR."
|
||||||
(let ((fields (split-string str "[\n\r]"))) ; break any balances
|
; break any balances with multi commodities into a list
|
||||||
; with multi commodities
|
(mapcar #'(lambda (st)
|
||||||
; into a list
|
(ledger-split-commodity-string st))
|
||||||
(mapcar #'(lambda (str)
|
(split-string str "[\n\r]")))
|
||||||
(ledger-split-commodity-string str))
|
|
||||||
fields)))
|
|
||||||
|
|
||||||
(defun -commodity (c1 c2)
|
(defun -commodity (c1 c2)
|
||||||
"Subtract C2 from C1, ensuring their commodities match."
|
"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))
|
(list (+ (car c1) (car c2)) (cadr c1))
|
||||||
(error "Can't add different commodities, %S to %S" c1 c2)))
|
(error "Can't add different commodities, %S to %S" c1 c2)))
|
||||||
|
|
||||||
(defun ledger-commodity-string-number-decimalize (number-string direction)
|
(defun ledger-strip (str char)
|
||||||
"Take NUMBER-STRING and ensure proper decimalization for use by string-to-number and number-to-string.
|
(let (new-str )
|
||||||
|
|
||||||
DIRECTION can be :to-user or :from-user. All math calculations
|
(dolist (ch (append str nil))
|
||||||
are done with decimal-period, some users may prefer decimal-comma
|
(unless (= ch char)
|
||||||
which must be translated both directions."
|
(setq new-str (append new-str (list ch)))))
|
||||||
(let ((val number-string))
|
(concat new-str)))
|
||||||
(if (assoc "decimal-comma" ledger-environment-alist)
|
|
||||||
(cond ((eq direction :from-user)
|
(defun ledger-string-to-number (str &optional decimal-comma)
|
||||||
;; change string to decimal-period
|
"improve builtin string-to-number by handling internationalization, and return nil of number can't be parsed"
|
||||||
(while (string-match "," val)
|
(let ((nstr (if (or decimal-comma
|
||||||
(setq val (replace-match "." nil nil val)))) ;; switch to period separator
|
(assoc "decimal-comma" ledger-environment-alist))
|
||||||
((eq direction :to-user)
|
(ledger-strip str ?.)
|
||||||
;; change to decimal-comma
|
(ledger-strip str ?,))))
|
||||||
(while (string-match "\\." val)
|
(while (string-match "," nstr)
|
||||||
(setq val (replace-match "," nil nil val)))) ;; gets rid of periods
|
(setq nstr (replace-match "." nil nil nstr)))
|
||||||
(t
|
(string-to-number nstr)))
|
||||||
(error "ledger-commodity-string-number-decimalize: direction not properly specified %S" direction)))
|
|
||||||
(while (string-match "," val)
|
(defun ledger-number-to-string (n &optional decimal-comma)
|
||||||
(setq val (replace-match "" nil nil val))))
|
(let ((str (number-to-string n)))
|
||||||
val))
|
(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.
|
"Return string representing C1.
|
||||||
Single character commodities are placed ahead of the value,
|
Single character commodities are placed ahead of the value,
|
||||||
longer ones are after the value."
|
longer ones are after the value."
|
||||||
(let ((val (ledger-commodity-string-number-decimalize
|
(let ((str (ledger-number-to-string (car c1)))
|
||||||
(number-to-string (car c1)) :to-user))
|
|
||||||
(commodity (cadr c1)))
|
(commodity (cadr c1)))
|
||||||
(if (> (length commodity) 1)
|
(if (> (length commodity) 1)
|
||||||
(concat val " " commodity)
|
(concat str " " commodity)
|
||||||
(concat commodity " " val))))
|
(concat commodity " " str))))
|
||||||
|
|
||||||
(defun ledger-read-commodity-string (prompt)
|
(defun ledger-read-commodity-string (prompt)
|
||||||
(let ((str (read-from-minibuffer
|
(let ((str (read-from-minibuffer
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ BEG, END, and LEN control how far it can align."
|
||||||
(let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t)))
|
(let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t)))
|
||||||
;; determine if there is an amount to edit
|
;; determine if there is an amount to edit
|
||||||
(if end-of-amount
|
(if end-of-amount
|
||||||
(let ((val (ledger-commodity-string-number-decimalize (match-string 0) :from-user)))
|
(let ((val (ledger-string-to-number (match-string 0))))
|
||||||
(goto-char (match-beginning 0))
|
(goto-char (match-beginning 0))
|
||||||
(delete-region (match-beginning 0) (match-end 0))
|
(delete-region (match-beginning 0) (match-end 0))
|
||||||
(calc)
|
(calc)
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
"-?[1-9][0-9.]*[,]?[0-9]*")
|
"-?[1-9][0-9.]*[,]?[0-9]*")
|
||||||
|
|
||||||
(defconst ledger-amount-decimal-period-regex
|
(defconst ledger-amount-decimal-period-regex
|
||||||
"-?[1-9][0-9.]*[.]?[0-9]*")
|
"-?[1-9][0-9,]*[.]?[0-9]*")
|
||||||
|
|
||||||
(defconst ledger-other-entries-regex
|
(defconst ledger-other-entries-regex
|
||||||
"\\(^[~=A-Za-z].+\\)+")
|
"\\(^[~=A-Za-z].+\\)+")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue