Showing 1 changed files with 35 additions and 16 deletions
+35 -16
csv2xlsx.go
... ...
@@ -8,10 +8,11 @@ import (
8 8
 	"fmt"
9 9
 	"github.com/tealeg/xlsx"
10 10
 	"os"
11
+	"path/filepath"
11 12
 	"strconv"
12 13
 	"strings"
13
-	"path/filepath"
14 14
 	"time"
15
+	"unicode/utf8"
15 16
 )
16 17
 
17 18
 var (
... ...
@@ -20,22 +21,23 @@ var (
20 21
 	parmSheet           string
21 22
 	parmInFile          string
22 23
 	parmOutFile         string
23
-	parmColSep          string
24
-	parmRowSep          string
24
+	parmColSep          rune
25 25
 	parmDateFormat      string
26 26
 	parmExcelDateFormat string
27
-	parmUseTitles       bool
27
+	parmNoHeader        bool
28 28
 	parmSilent          bool
29 29
 	parmHelp            bool
30 30
 	parmAbortOnError    bool
31
-	parmShowVersion		bool
31
+	parmShowVersion     bool
32
+	parmAutoFormula     bool
32 33
 	rowRangeParsed      map[int]string
33 34
 	colRangeParsed      map[int]string
34 35
 	workBook            *xlsx.File
35 36
 	workSheet           *xlsx.Sheet
36 37
 	rightAligned        *xlsx.Style
37
-	buildTimestamp		string
38
-	versionInfo			string
38
+	buildTimestamp      string
39
+	versionInfo         string
40
+	tmpStr              string
39 41
 )
40 42
 
41 43
 // parseCommaGroup parses a single comma group (x or x-y),
... ...
@@ -103,29 +105,38 @@ func parseCommandLine() {
103 105
 	flag.StringVar(&parmCols, "columns", "", "column range to use (see below)")
104 106
 	flag.StringVar(&parmRows, "rows", "", "list of line numbers to use (1,2,8 or 1,3-14,28)")
105 107
 	flag.StringVar(&parmSheet, "sheet", "fromCSV", "tab name of the Excel sheet")
106
-	flag.StringVar(&parmColSep, "colsep", "|", "column separator (default '|') ")
107
-	flag.StringVar(&parmRowSep, "rowsep", "\n", "row separator (default LF) ")
108
-	flag.BoolVar(&parmUseTitles, "usetitles", true, "use first row as titles (will force string type)")
108
+	flag.StringVar(&tmpStr, "colsep", "|", "column separator (default '|') ")
109
+	// not settable with csv reader
110
+	//flag.StringVar(&parmRowSep, "rowsep", "\n", "row separator (default LF) ")
111
+	flag.BoolVar(&parmNoHeader, "noheader", false, "no headers in first line, only data lines (default false)")
109 112
 	flag.BoolVar(&parmAbortOnError, "abortonerror", false, "abort program on first invalid cell data type")
110 113
 	flag.BoolVar(&parmSilent, "silent", false, "do not display progress messages")
114
+	flag.BoolVar(&parmAutoFormula, "autoformula", false, "automatically format string starting with = as formulae")
111 115
 	flag.BoolVar(&parmHelp, "help", false, "display usage information")
112 116
 	flag.BoolVar(&parmHelp, "h", false, "display usage information")
113 117
 	flag.BoolVar(&parmHelp, "?", false, "display usage information")
114 118
 	flag.BoolVar(&parmShowVersion, "version", false, "display version information")
115 119
 	flag.Parse()
116 120
 
121
+	t, err := strconv.Unquote(`"` + tmpStr + `"`)
122
+	if err != nil {
123
+		fmt.Println("Invalid column separator specified, exiting.")
124
+		os.Exit(1)
125
+	}
126
+	parmColSep, _ = utf8.DecodeRuneInString(t)
127
+
117 128
 	if parmShowVersion {
118 129
 		fmt.Println("Version ", versionInfo, ", Build timestamp ", buildTimestamp)
119 130
 		os.Exit(0)
120 131
 	}
121 132
 
122 133
 	if parmHelp {
123
-		fmt.Printf("You are running verion %s of %s\n\n", versionInfo, filepath.Base(os.Args[0]))
134
+		fmt.Printf("You are running version %s of %s\n\n", versionInfo, filepath.Base(os.Args[0]))
124 135
 		flag.Usage()
125 136
 		fmt.Println(`
126 137
         Column ranges are a comma-separated list of numbers (e.g. 1,4,8,16), intervals (e.g. 0-4,18-32) or a combination.
127 138
         Each comma group can take a type specifiers for the column,
128
-        one of "text", "number", "integer", "currency", date" or "standard",
139
+        one of "text", "number", "integer", "currency", date", "standard" or "formula"
129 140
         separated from numbers with a colon (e.g. 0:text,3-16:number,17:date)
130 141
 		`)
131 142
 		os.Exit(1)
... ...
@@ -148,7 +159,8 @@ func loadInputFile(filename string) (rows [][]string) {
148 159
 	}
149 160
 	// use csv reader to read entire file
150 161
 	r := csv.NewReader(bufio.NewReader(f))
151
-	r.Comma = []rune(parmColSep)[0]
162
+	r.Comma = parmColSep
163
+	r.FieldsPerRecord = -1
152 164
 	r.LazyQuotes = true
153 165
 	rows, err = r.ReadAll()
154 166
 	if err != nil {
... ...
@@ -180,11 +192,15 @@ func setRangeInformation(rowCount, colCount int) {
180 192
 // it outputs an error message and ignores the value
181 193
 func writeCellContents(cell *xlsx.Cell, colString, colType string, rownum, colnum int) bool {
182 194
 	success := true
195
+	// only convert to formula if the user specified --autoformula,
196
+	// otherwise use the defined type from column range -- for lazy people :-)
197
+	if parmAutoFormula && []rune(colString)[0] == '=' {
198
+		colType = "formula"
199
+	}
183 200
 	switch colType {
184 201
 	case "text":
185 202
 		cell.SetString(colString)
186
-	case "number":
187
-	case "currency":
203
+	case "number","currency":
188 204
 		floatVal, err := strconv.ParseFloat(colString, 64)
189 205
 		if err != nil {
190 206
 			fmt.Println(fmt.Sprintf("Cell (%d,%d) is not a valid number, value: %s", rownum, colnum, colString))
... ...
@@ -218,6 +234,9 @@ func writeCellContents(cell *xlsx.Cell, colString, colType string, rownum, colnu
218 234
 				cell.NumFmt = parmExcelDateFormat
219 235
 			}
220 236
 		}
237
+	case "formula":
238
+		// colstring =<formula>
239
+		cell.SetFormula(colString[1:])
221 240
 	default:
222 241
 		cell.SetValue(colString)
223 242
 	}
... ...
@@ -235,7 +254,7 @@ func processDataColumns(excelRow *xlsx.Row, rownum int, csvLine []string) {
235 254
 		colType, processColumn := colRangeParsed[colnum]
236 255
 		if processColumn {
237 256
 			cell := excelRow.AddCell()
238
-			if rownum == 0 && parmUseTitles {
257
+			if rownum == 0 && !parmNoHeader {
239 258
 				// special case for the title row
240 259
 				cell.SetString(csvLine[colnum])
241 260
 				if colType == "number" || colType == "currency" {