r17110 - gnucash/branches/2.2/src/import-export/qif-import - [r17086] Bug #527886: Add support for QIF numeric formats of 12'345.67 as produced by Quicken 4.
Andreas Köhler
andi5 at cvs.gnucash.org
Sun Apr 20 15:24:39 EDT 2008
Author: andi5
Date: 2008-04-20 15:24:39 -0400 (Sun, 20 Apr 2008)
New Revision: 17110
Trac: http://svn.gnucash.org/trac/changeset/17110
Modified:
gnucash/branches/2.2/src/import-export/qif-import/file-format.txt
gnucash/branches/2.2/src/import-export/qif-import/qif-parse.scm
gnucash/branches/2.2/src/import-export/qif-import/qif-utils.scm
Log:
[r17086] Bug #527886: Add support for QIF numeric formats of 12'345.67 as produced by Quicken 4.
Also support 12'345,67 for completeness. Added documentation for this
format, along with investment 'N' lines. Added two new string
manipulation utility procedures for simplification. Mild whitespace and
readability cleanup.
Committed by cedayiv.
Modified: gnucash/branches/2.2/src/import-export/qif-import/file-format.txt
===================================================================
--- gnucash/branches/2.2/src/import-export/qif-import/file-format.txt 2008-04-20 19:24:30 UTC (rev 17109)
+++ gnucash/branches/2.2/src/import-export/qif-import/file-format.txt 2008-04-20 19:24:39 UTC (rev 17110)
@@ -224,7 +224,7 @@
General Notes:
Dates:
------
+------
Dates in US QIF files are usually in the format MM/DD/YY, although
four-digit years are not uncommon. Dates sometimes occur without the
@@ -238,19 +238,65 @@
Monetary Amounts:
-----------------
-These may occur in either US or Euro format:
+These typically occur in either US or European format:
-10,000.00 Ten Thousand Dollars
-10.000,00 Ten Thousand Francs
+10,000.00 Ten Thousand Dollars (US format)
+10.000,00 Ten Thousand Francs (European format)
-Within a given QIF file, the usage of US or Euro numeric format
+An apostrophe is also used in some cases:
+
+10'000.00 Ten Thousand Dollars (Quicken 4)
+10'000,00 Ten Thousand Francs (unconfirmed)
+
+Within a given QIF file, the usage of a particular numeric format
appears to be consistent within a particular field but may be
different from one field to another. For example, the Share Amount
-field can be in Euro format but the Split Amount in US. No
+field can be in European format but the Split Amount in US. No
radix-point is required and no limit on decimal places is evident, so
it's possible to see the number "1,000" meaning "1 franc per share"
"1,000" meaning "one thousand shares" in the same transaction (!).
+Investment Actions:
+-------------------
+The N line of investment transactions specifies the "action" of the
+transaction. Although not a complete list, possible values include
+the following:
+
+QIF N Line Notes
+============ =====
+Buy Buy shares.
+BuyX Buy shares. Used with an L line.
+Cash Miscellaneous cash transaction. Used with an L line.
+ContribX Same as XIn. Used for tax-advantaged accounts.
+CvrShrt Buy shares to cover a short sale.
+Div Dividend received.
+DivX Dividend received. For use with an L line.
+Exercise Exercise an option.
+Expire Mark an option as expired. (Uses D, N, Y & M lines)
+Grant Receive a grant of stock options.
+IntInc Interest received.
+IntIncX Interest received. For use with an L line.
+MargInt Margin interest paid.
+MargIntX Margin interest paid. For use with an L line.
+MiscExp Miscellaneous expense.
+MiscExpX Miscellaneous expense. For use with an L line.
+MiscInc Miscellaneous income.
+MiscIncX Miscellaneous income. For use with an L line.
+ReinvDiv Reinvested dividend.
+ReinvInt Reinvested interest.
+Reminder Reminder. (Uses D, N, C & M lines)
+RtrnCap Return of capital.
+RtrnCapX Return of capital. For use with an L line.
+Sell Sell shares.
+SellX Sell shares. For use with an L line.
+ShtSell Short sale.
+ShrsIn Deposit shares.
+ShrsOut Withdraw shares.
+StkSplit Stock split.
+XIn Transfer cash from another account.
+XOut Transfer cash to another account.
+Vest Mark options as vested. (Uses N, Y, Q, C & M lines)
+
Category/Transfer/Class line:
-----------------------------
@@ -274,5 +320,3 @@
NMiscExpX
T1000.00
Lexpense category/expense class|[Transfer account]/transfer class
-
-
Modified: gnucash/branches/2.2/src/import-export/qif-import/qif-parse.scm
===================================================================
--- gnucash/branches/2.2/src/import-export/qif-import/qif-parse.scm 2008-04-20 19:24:30 UTC (rev 17109)
+++ gnucash/branches/2.2/src/import-export/qif-import/qif-parse.scm 2008-04-20 19:24:39 UTC (rev 17110)
@@ -19,11 +19,11 @@
(define decimal-radix-regexp
(make-regexp
- "^ *\\$?[+-]?\\$?[0-9]+$|^ *\\$?[+-]?\\$?[0-9]?[0-9]?[0-9]?(,[0-9][0-9][0-9])*(\\.[0-9]*)? *$|^ *\\$?[+-]?\\$?[0-9]+\\.[0-9]* *$"))
+ "^ *\\$?[+-]?\\$?[0-9]+$|^ *\\$?[+-]?\\$?[0-9]?[0-9]?[0-9]?([,'][0-9][0-9][0-9])*(\\.[0-9]*)? *$|^ *\\$?[+-]?\\$?[0-9]+\\.[0-9]* *$"))
(define comma-radix-regexp
(make-regexp
- "^ *\\$?[+-]?\\$?[0-9]+$|^ *\\$?[+-]?\\$?[0-9]?[0-9]?[0-9]?(\\.[0-9][0-9][0-9])*(,[0-9]*)? *$|^ *\\$?[+-]?\\$?[0-9]+,[0-9]* *$"))
+ "^ *\\$?[+-]?\\$?[0-9]+$|^ *\\$?[+-]?\\$?[0-9]?[0-9]?[0-9]?([\\.'][0-9][0-9][0-9])*(,[0-9]*)? *$|^ *\\$?[+-]?\\$?[0-9]+,[0-9]* *$"))
(define integer-regexp (make-regexp "^\\$?[+-]?\\$?[0-9]+ *$"))
@@ -89,26 +89,26 @@
(set! fixed-string
(substring year-string 2 (string-length year-string))))
(set! fixed-string year-string))
-
+
;; now the string should just have a number in it plus some
;; optional trailing space.
(set! post-read-value
(with-input-from-string fixed-string
(lambda () (read))))
-
+
(cond
;; 2-digit numbers less than the window size are interpreted to
;; be post-2000.
((and (integer? post-read-value)
(< post-read-value y2k-threshold))
(set! y2k-fixed-value (+ 2000 post-read-value)))
-
+
;; there's a common bug in printing post-2000 dates that
;; prints 2000 as 19100 etc.
((and (integer? post-read-value)
(> post-read-value 19000))
(set! y2k-fixed-value (+ 1900 (- post-read-value 19000))))
-
+
;; normal dates represented in unix years (i.e. year-1900, so
;; 2000 => 100.) We also want to allow full year specifications,
;; (i.e. 1999, 2001, etc) and there's a point at which you can't
@@ -120,11 +120,11 @@
((and (integer? post-read-value)
(< post-read-value 1902))
(set! y2k-fixed-value (+ 1900 post-read-value)))
-
+
;; this is a normal, 4-digit year spec (1999, 2000, etc).
((integer? post-read-value)
(set! y2k-fixed-value post-read-value))
-
+
;; No idea what the string represents. Maybe a new bug in Quicken!
(#t
(gnc:warn "qif-file:fix-year: ay caramba! What is this? ["
@@ -326,14 +326,14 @@
(with-input-from-string elt
(lambda () (read))))
date-parts))
-
+
(let ((possibilities possible-formats)
(n1 (car numeric-date-parts))
(n2 (cadr numeric-date-parts))
(n3 (caddr numeric-date-parts))
(s1 (car date-parts))
(s3 (caddr date-parts)))
-
+
;; filter the possibilities to eliminate (hopefully)
;; all but one
(if (or (not (number? n1)) (> n1 12))
@@ -344,22 +344,22 @@
(set! possibilities (delq 'd-m-y possibilities)))
(if (or (not (number? n1)) (< n1 1))
(set! possibilities (delq 'm-d-y possibilities)))
-
+
(if (or (not (number? n2)) (> n2 12))
(begin
(set! possibilities (delq 'd-m-y possibilities))
(set! possibilities (delq 'y-m-d possibilities))))
-
+
(if (or (not (number? n2)) (> n2 31))
(begin
(set! possibilities (delq 'm-d-y possibilities))
(set! possibilities (delq 'y-d-m possibilities))))
-
+
(if (or (not (number? n3)) (> n3 12))
(set! possibilities (delq 'y-d-m possibilities)))
(if (or (not (number? n3)) (> n3 31))
(set! possibilities (delq 'y-m-d possibilities)))
-
+
(if (or (not (number? n3)) (< n3 1))
(set! possibilities (delq 'y-m-d possibilities)))
(if (or (not (number? n3)) (< n3 1))
@@ -449,14 +449,14 @@
(match:substring m 2)
(match:substring m 3)))))
))))
-
+
;; get the strings into numbers (but keep the strings around)
(set! numeric-date-parts
(map (lambda (elt)
(with-input-from-string elt
(lambda () (read))))
date-parts))
-
+
;; if the date parts list doesn't have 3 parts, we're in
;; trouble
(if (not (eq? 3 (length date-parts)))
@@ -473,7 +473,7 @@
(gnc:warn "qif-parse:parse-date/format: "
"format is d/m/y, but date is ["
date-string "]."))))
-
+
((m-d-y)
(let ((m (car numeric-date-parts))
(d (cadr numeric-date-parts))
@@ -484,7 +484,7 @@
(gnc:warn "qif-parse:parse-date/format: "
"format is m/d/y, but date is ["
date-string "]."))))
-
+
((y-m-d)
(let ((y (qif-parse:fix-year (car date-parts) 50))
(m (cadr numeric-date-parts))
@@ -495,7 +495,7 @@
(gnc:warn "qif-parse:parse-date/format: "
"format is y/m/d, but date is ["
date-string "]."))))
-
+
((y-d-m)
(let ((y (qif-parse:fix-year (car date-parts) 50))
(d (cadr numeric-date-parts))
@@ -553,13 +553,9 @@
(define (qif-parse:parse-number/format value-string format)
(case format
((decimal)
- (let* ((filtered-string
- (string-remove-char
- (string-remove-char value-string #\,)
- #\$))
- (read-val
- (with-input-from-string filtered-string
- (lambda () (read)))))
+ (let* ((filtered-string (string-remove-chars value-string ",$'"))
+ (read-val (with-input-from-string filtered-string
+ (lambda () (read)))))
(if (number? read-val)
(double-to-gnc-numeric
(+ 0.0 read-val) GNC-DENOM-AUTO
@@ -568,15 +564,11 @@
GNC-RND-ROUND))
(gnc-numeric-zero))))
((comma)
- (let* ((filtered-string
- (string-remove-char
- (string-replace-char!
- (string-remove-char value-string #\.)
- #\, #\.)
- #\$))
- (read-val
- (with-input-from-string filtered-string
- (lambda () (read)))))
+ (let* ((filtered-string (string-replace-char
+ (string-remove-chars value-string ".$'")
+ #\, #\.))
+ (read-val (with-input-from-string filtered-string
+ (lambda () (read)))))
(if (number? read-val)
(double-to-gnc-numeric
(+ 0.0 read-val) GNC-DENOM-AUTO
@@ -585,10 +577,9 @@
GNC-RND-ROUND))
(gnc-numeric-zero))))
((integer)
- (let ((read-val
- (with-input-from-string
- (string-remove-char value-string #\$)
- (lambda () (read)))))
+ (let ((read-val (with-input-from-string (string-remove-char value-string
+ #\$)
+ (lambda () (read)))))
(if (number? read-val)
(double-to-gnc-numeric
(+ 0.0 read-val) 1 GNC-RND-ROUND)
Modified: gnucash/branches/2.2/src/import-export/qif-import/qif-utils.scm
===================================================================
--- gnucash/branches/2.2/src/import-export/qif-import/qif-utils.scm 2008-04-20 19:24:30 UTC (rev 17109)
+++ gnucash/branches/2.2/src/import-export/qif-import/qif-utils.scm 2008-04-20 19:24:39 UTC (rev 17110)
@@ -5,6 +5,9 @@
;;; Bill Gribble <grib at billgribble.com> 20 Feb 2000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(use-modules (srfi srfi-13))
+
+
(define (simple-filter pred list)
(let ((retval '()))
(map (lambda (elt)
@@ -45,10 +48,34 @@
(make-string 1 char)))))
(regexp-substitute/global #f rexpstr str 'pre 'post)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; string-remove-chars
+;;
+;; Removes all characters in string "chars" from string "str".
+;; Example: (string-remove-chars "abcd" "cb") returns "ad".
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (string-remove-chars str chars)
+ (string-delete str (lambda (c) (string-index chars c))))
+
+
(define (string-char-count str char)
(length (simple-filter (lambda (elt) (eq? elt char))
(string->list str))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; string-replace-char
+;;
+;; Replaces all occurrences of char "old" with char "new".
+;; Example: (string-replace-char "foo" #\o #\c) returns "fcc".
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (string-replace-char str old new)
+ (string-map (lambda (c) (if (char=? c old) new c)) str))
+
+
(define (string-replace-char! str old new)
(let ((rexpstr
(if (not (eq? old #\.))
More information about the gnucash-changes
mailing list