...
|
...
|
@@ -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" {
|