cell.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. package xlsx
  2. import (
  3. "fmt"
  4. "math"
  5. "strconv"
  6. "strings"
  7. )
  8. // CellType is an int type for storing metadata about the data type in the cell.
  9. type CellType int
  10. // Known types for cell values.
  11. const (
  12. CellTypeString CellType = iota
  13. CellTypeFormula
  14. CellTypeNumeric
  15. CellTypeBool
  16. CellTypeInline
  17. CellTypeError
  18. )
  19. // Cell is a high level structure intended to provide user access to
  20. // the contents of Cell within an xlsx.Row.
  21. type Cell struct {
  22. Row *Row
  23. Value string
  24. formula string
  25. style *Style
  26. numFmt string
  27. date1904 bool
  28. Hidden bool
  29. HMerge int
  30. VMerge int
  31. cellType CellType
  32. }
  33. // CellInterface defines the public API of the Cell.
  34. type CellInterface interface {
  35. String() string
  36. FormattedValue() string
  37. }
  38. // NewCell creates a cell and adds it to a row.
  39. func NewCell(r *Row) *Cell {
  40. return &Cell{style: NewStyle(), Row: r}
  41. }
  42. // Merge with other cells, horizontally and/or vertically.
  43. func (c *Cell) Merge(hcells, vcells int) {
  44. c.HMerge = hcells
  45. c.VMerge = vcells
  46. }
  47. // Type returns the CellType of a cell. See CellType constants for more details.
  48. func (c *Cell) Type() CellType {
  49. return c.cellType
  50. }
  51. // SetString sets the value of a cell to a string.
  52. func (c *Cell) SetString(s string) {
  53. c.Value = s
  54. c.formula = ""
  55. c.cellType = CellTypeString
  56. }
  57. // String returns the value of a Cell as a string.
  58. func (c *Cell) String() string {
  59. return c.FormattedValue()
  60. }
  61. // SetFloat sets the value of a cell to a float.
  62. func (c *Cell) SetFloat(n float64) {
  63. c.SetFloatWithFormat(n, "general")
  64. }
  65. /*
  66. The following are samples of format samples.
  67. * "0.00e+00"
  68. * "0", "#,##0"
  69. * "0.00", "#,##0.00", "@"
  70. * "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)"
  71. * "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)"
  72. * "0%", "0.00%"
  73. * "0.00e+00", "##0.0e+0"
  74. */
  75. // SetFloatWithFormat sets the value of a cell to a float and applies
  76. // formatting to the cell.
  77. func (c *Cell) SetFloatWithFormat(n float64, format string) {
  78. // beauty the output when the float is small enough
  79. if n != 0 && n < 0.00001 {
  80. c.Value = strconv.FormatFloat(n, 'e', -1, 64)
  81. } else {
  82. c.Value = strconv.FormatFloat(n, 'f', -1, 64)
  83. }
  84. c.numFmt = format
  85. c.formula = ""
  86. c.cellType = CellTypeNumeric
  87. }
  88. // Float returns the value of cell as a number.
  89. func (c *Cell) Float() (float64, error) {
  90. f, err := strconv.ParseFloat(c.Value, 64)
  91. if err != nil {
  92. return math.NaN(), err
  93. }
  94. return f, nil
  95. }
  96. // SetInt64 sets a cell's value to a 64-bit integer.
  97. func (c *Cell) SetInt64(n int64) {
  98. c.Value = fmt.Sprintf("%d", n)
  99. c.numFmt = "0"
  100. c.formula = ""
  101. c.cellType = CellTypeNumeric
  102. }
  103. // Int64 returns the value of cell as 64-bit integer.
  104. func (c *Cell) Int64() (int64, error) {
  105. f, err := strconv.ParseInt(c.Value, 10, 64)
  106. if err != nil {
  107. return -1, err
  108. }
  109. return f, nil
  110. }
  111. // SetInt sets a cell's value to an integer.
  112. func (c *Cell) SetInt(n int) {
  113. c.Value = fmt.Sprintf("%d", n)
  114. c.numFmt = "0"
  115. c.formula = ""
  116. c.cellType = CellTypeNumeric
  117. }
  118. // Int returns the value of cell as integer.
  119. // Has max 53 bits of precision
  120. // See: float64(int64(math.MaxInt))
  121. func (c *Cell) Int() (int, error) {
  122. f, err := strconv.ParseFloat(c.Value, 64)
  123. if err != nil {
  124. return -1, err
  125. }
  126. return int(f), nil
  127. }
  128. // SetBool sets a cell's value to a boolean.
  129. func (c *Cell) SetBool(b bool) {
  130. if b {
  131. c.Value = "1"
  132. } else {
  133. c.Value = "0"
  134. }
  135. c.cellType = CellTypeBool
  136. }
  137. // Bool returns a boolean from a cell's value.
  138. // TODO: Determine if the current return value is
  139. // appropriate for types other than CellTypeBool.
  140. func (c *Cell) Bool() bool {
  141. // If bool, just return the value.
  142. if c.cellType == CellTypeBool {
  143. return c.Value == "1"
  144. }
  145. // If numeric, base it on a non-zero.
  146. if c.cellType == CellTypeNumeric {
  147. return c.Value != "0"
  148. }
  149. // Return whether there's an empty string.
  150. return c.Value != ""
  151. }
  152. // SetFormula sets the format string for a cell.
  153. func (c *Cell) SetFormula(formula string) {
  154. c.formula = formula
  155. c.cellType = CellTypeFormula
  156. }
  157. // Formula returns the formula string for the cell.
  158. func (c *Cell) Formula() string {
  159. return c.formula
  160. }
  161. // GetStyle returns the Style associated with a Cell
  162. func (c *Cell) GetStyle() *Style {
  163. return c.style
  164. }
  165. // SetStyle sets the style of a cell.
  166. func (c *Cell) SetStyle(style *Style) {
  167. c.style = style
  168. }
  169. // GetNumberFormat returns the number format string for a cell.
  170. func (c *Cell) GetNumberFormat() string {
  171. return c.numFmt
  172. }
  173. func (c *Cell) formatToFloat(format string) string {
  174. f, err := strconv.ParseFloat(c.Value, 64)
  175. if err != nil {
  176. return err.Error()
  177. }
  178. return fmt.Sprintf(format, f)
  179. }
  180. func (c *Cell) formatToInt(format string) string {
  181. f, err := strconv.ParseFloat(c.Value, 64)
  182. if err != nil {
  183. return err.Error()
  184. }
  185. return fmt.Sprintf(format, int(f))
  186. }
  187. // FormattedValue returns the formatted version of the value.
  188. // If it's a string type, c.Value will just be returned. Otherwise,
  189. // it will attempt to apply Excel formatting to the value.
  190. func (c *Cell) FormattedValue() string {
  191. var numberFormat = c.GetNumberFormat()
  192. if isTimeFormat(numberFormat) {
  193. return parseTime(c)
  194. }
  195. switch numberFormat {
  196. case "general", "@":
  197. return c.Value
  198. case "0", "#,##0":
  199. return c.formatToInt("%d")
  200. case "0.00", "#,##0.00":
  201. return c.formatToFloat("%.2f")
  202. case "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)":
  203. f, err := strconv.ParseFloat(c.Value, 64)
  204. if err != nil {
  205. return err.Error()
  206. }
  207. if f < 0 {
  208. i := int(math.Abs(f))
  209. return fmt.Sprintf("(%d)", i)
  210. }
  211. i := int(f)
  212. return fmt.Sprintf("%d", i)
  213. case "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)":
  214. f, err := strconv.ParseFloat(c.Value, 64)
  215. if err != nil {
  216. return err.Error()
  217. }
  218. if f < 0 {
  219. return fmt.Sprintf("(%.2f)", f)
  220. }
  221. return fmt.Sprintf("%.2f", f)
  222. case "0%":
  223. f, err := strconv.ParseFloat(c.Value, 64)
  224. if err != nil {
  225. return err.Error()
  226. }
  227. f = f * 100
  228. return fmt.Sprintf("%d%%", int(f))
  229. case "0.00%":
  230. f, err := strconv.ParseFloat(c.Value, 64)
  231. if err != nil {
  232. return err.Error()
  233. }
  234. f = f * 100
  235. return fmt.Sprintf("%.2f%%", f)
  236. case "0.00e+00", "##0.0e+0":
  237. return c.formatToFloat("%e")
  238. }
  239. return c.Value
  240. }
  241. // parseTime returns a string parsed using time.Time
  242. func parseTime(c *Cell) string {
  243. f, err := strconv.ParseFloat(c.Value, 64)
  244. if err != nil {
  245. return err.Error()
  246. }
  247. val := TimeFromExcelTime(f, c.date1904)
  248. format := c.GetNumberFormat()
  249. // Replace Excel placeholders with Go time placeholders.
  250. // For example, replace yyyy with 2006. These are in a specific order,
  251. // due to the fact that m is used in month, minute, and am/pm. It would
  252. // be easier to fix that with regular expressions, but if it's possible
  253. // to keep this simple it would be easier to maintain.
  254. replacements := []struct{ xltime, gotime string }{
  255. {"yyyy", "2006"},
  256. {"yy", "06"},
  257. {"dd", "02"},
  258. {"d", "2"},
  259. {"mmm", "Jan"},
  260. {"mmss", "0405"},
  261. {"ss", "05"},
  262. {"hh", "15"},
  263. {"h", "3"},
  264. {"mm:", "04:"},
  265. {":mm", ":04"},
  266. {"mm", "01"},
  267. {"am/pm", "pm"},
  268. {"m/", "1/"},
  269. {".0", ".9999"},
  270. }
  271. for _, repl := range replacements {
  272. format = strings.Replace(format, repl.xltime, repl.gotime, 1)
  273. }
  274. // If the hour is optional, strip it out, along with the
  275. // possible dangling colon that would remain.
  276. if val.Hour() < 1 {
  277. format = strings.Replace(format, "]:", "]", 1)
  278. format = strings.Replace(format, "[3]", "", 1)
  279. format = strings.Replace(format, "[15]", "", 1)
  280. } else {
  281. format = strings.Replace(format, "[3]", "3", 1)
  282. format = strings.Replace(format, "[15]", "15", 1)
  283. }
  284. return val.Format(format)
  285. }
  286. // isTimeFormat checks whether an Excel format string represents
  287. // a time.Time.
  288. func isTimeFormat(format string) bool {
  289. dateParts := []string{
  290. "yy", "hh", "am", "pm", "ss", "mm", ":",
  291. }
  292. for _, part := range dateParts {
  293. if strings.Contains(format, part) {
  294. return true
  295. }
  296. }
  297. return false
  298. }