number_format.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. // Copyright (c) 2014-2021 Thomas Fussell
  2. // Copyright (c) 2010-2015 openpyxl
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE
  21. //
  22. // @license: http://www.opensource.org/licenses/mit-license.php
  23. // @author: see AUTHORS file
  24. #include <algorithm>
  25. #include <cctype>
  26. #include <unordered_map>
  27. #include <vector>
  28. #include <xlnt/styles/number_format.hpp>
  29. #include <xlnt/utils/datetime.hpp>
  30. #include <xlnt/utils/exceptions.hpp>
  31. #include <detail/number_format/number_formatter.hpp>
  32. namespace {
  33. const std::unordered_map<std::size_t, xlnt::number_format> &builtin_formats()
  34. {
  35. static std::unordered_map<std::size_t, xlnt::number_format> formats;
  36. if (formats.size() == 0)
  37. {
  38. const std::unordered_map<std::size_t, std::string> format_strings{
  39. {0, "General"},
  40. {1, "0"},
  41. {2, "0.00"},
  42. {3, "#,##0"},
  43. {4, "#,##0.00"},
  44. {9, "0%"},
  45. {10, "0.00%"},
  46. {11, "0.00E+00"},
  47. {12, "# ?/?"},
  48. {13, "# \?\?/??"}, // escape trigraph
  49. {14, "mm-dd-yy"},
  50. {15, "d-mmm-yy"},
  51. {16, "d-mmm"},
  52. {17, "mmm-yy"},
  53. {18, "h:mm AM/PM"},
  54. {19, "h:mm:ss AM/PM"},
  55. {20, "h:mm"},
  56. {21, "h:mm:ss"},
  57. {22, "m/d/yy h:mm"},
  58. {37, "#,##0 ;(#,##0)"},
  59. {38, "#,##0 ;[Red](#,##0)"},
  60. {39, "#,##0.00;(#,##0.00)"},
  61. {40, "#,##0.00;[Red](#,##0.00)"},
  62. // 41-44 aren't in the ECMA 376 v4 standard, but Libre Office uses them
  63. {41, "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)"},
  64. {42, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)"},
  65. {43, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)"},
  66. {44, "_(\"$\"* #,##0.00_)_(\"$\"* \\(#,##0.00\\)_(\"$\"* \"-\"??_)_(@_)"},
  67. {45, "mm:ss"},
  68. {46, "[h]:mm:ss"},
  69. {47, "mmss.0"},
  70. {48, "##0.0E+0"},
  71. {49, "@"}};
  72. for (auto format_string_pair : format_strings)
  73. {
  74. formats[format_string_pair.first] =
  75. xlnt::number_format(format_string_pair.second, format_string_pair.first);
  76. }
  77. }
  78. return formats;
  79. }
  80. } // namespace
  81. namespace xlnt {
  82. const number_format number_format::general()
  83. {
  84. return builtin_formats().at(0);
  85. }
  86. const number_format number_format::text()
  87. {
  88. return builtin_formats().at(49);
  89. }
  90. const number_format number_format::number()
  91. {
  92. return builtin_formats().at(1);
  93. }
  94. const number_format number_format::number_00()
  95. {
  96. return builtin_formats().at(2);
  97. }
  98. const number_format number_format::number_comma_separated1()
  99. {
  100. return builtin_formats().at(4);
  101. }
  102. const number_format number_format::percentage()
  103. {
  104. return builtin_formats().at(9);
  105. }
  106. const number_format number_format::percentage_00()
  107. {
  108. return builtin_formats().at(10);
  109. }
  110. const number_format number_format::date_yyyymmdd2()
  111. {
  112. static const number_format format = number_format("yyyy-mm-dd");
  113. return format;
  114. }
  115. const number_format number_format::date_yymmdd()
  116. {
  117. static const number_format format = number_format("yy-mm-dd");
  118. return format;
  119. }
  120. const number_format number_format::date_ddmmyyyy()
  121. {
  122. static const number_format format = number_format("dd/mm/yy");
  123. return format;
  124. }
  125. const number_format number_format::date_dmyslash()
  126. {
  127. static const number_format format = number_format("d/m/yy");
  128. return format;
  129. }
  130. const number_format number_format::date_dmyminus()
  131. {
  132. static const number_format format = number_format("d-m-yy");
  133. return format;
  134. }
  135. const number_format number_format::date_dmminus()
  136. {
  137. static const number_format format = number_format("d-m");
  138. return format;
  139. }
  140. const number_format number_format::date_myminus()
  141. {
  142. static const number_format format = number_format("m-yy");
  143. return format;
  144. }
  145. const number_format number_format::date_xlsx14()
  146. {
  147. return builtin_formats().at(14);
  148. }
  149. const number_format number_format::date_xlsx15()
  150. {
  151. return builtin_formats().at(15);
  152. }
  153. const number_format number_format::date_xlsx16()
  154. {
  155. return builtin_formats().at(16);
  156. }
  157. const number_format number_format::date_xlsx17()
  158. {
  159. return builtin_formats().at(17);
  160. }
  161. const number_format number_format::date_xlsx22()
  162. {
  163. return builtin_formats().at(22);
  164. }
  165. const number_format number_format::date_datetime()
  166. {
  167. static const number_format format = number_format("yyyy-mm-dd h:mm:ss");
  168. return format;
  169. }
  170. const number_format number_format::date_time1()
  171. {
  172. return builtin_formats().at(18);
  173. }
  174. const number_format number_format::date_time2()
  175. {
  176. return builtin_formats().at(19);
  177. }
  178. const number_format number_format::date_time3()
  179. {
  180. return builtin_formats().at(20);
  181. }
  182. const number_format number_format::date_time4()
  183. {
  184. return builtin_formats().at(21);
  185. }
  186. const number_format number_format::date_time5()
  187. {
  188. return builtin_formats().at(45);
  189. }
  190. const number_format number_format::date_time6()
  191. {
  192. return builtin_formats().at(21);
  193. }
  194. number_format::number_format()
  195. : number_format("General", 0)
  196. {
  197. }
  198. number_format::number_format(std::size_t id)
  199. : number_format(from_builtin_id(id))
  200. {
  201. }
  202. number_format::number_format(const std::string &format_string)
  203. : format_string_(format_string)
  204. {
  205. }
  206. number_format::number_format(const std::string &format, std::size_t id)
  207. {
  208. format_string(format, id);
  209. }
  210. bool number_format::is_builtin_format(std::size_t builtin_id)
  211. {
  212. return builtin_formats().find(builtin_id) != builtin_formats().end();
  213. }
  214. const number_format &number_format::from_builtin_id(std::size_t builtin_id)
  215. {
  216. if (!is_builtin_format(builtin_id))
  217. {
  218. throw invalid_parameter();
  219. }
  220. return builtin_formats().at(builtin_id);
  221. }
  222. std::string number_format::format_string() const
  223. {
  224. return format_string_;
  225. }
  226. void number_format::format_string(const std::string &format_string)
  227. {
  228. format_string_ = format_string;
  229. id_ = 0;
  230. for (const auto &pair : builtin_formats())
  231. {
  232. if (pair.second.format_string() == format_string)
  233. {
  234. id_ = pair.first;
  235. break;
  236. }
  237. }
  238. }
  239. void number_format::format_string(const std::string &format_string, std::size_t id)
  240. {
  241. format_string_ = format_string;
  242. id_ = id;
  243. }
  244. bool number_format::has_id() const
  245. {
  246. return id_.is_set();
  247. }
  248. void number_format::id(std::size_t id)
  249. {
  250. id_ = id;
  251. }
  252. std::size_t number_format::id() const
  253. {
  254. if (!has_id())
  255. {
  256. throw invalid_attribute();
  257. }
  258. return id_.get();
  259. }
  260. bool number_format::is_date_format() const
  261. {
  262. detail::number_format_parser p(format_string_);
  263. p.parse();
  264. auto parsed = p.result();
  265. bool any_datetime = false;
  266. bool any_timedelta = false;
  267. for (const auto &section : parsed)
  268. {
  269. if (section.is_datetime)
  270. {
  271. any_datetime = true;
  272. }
  273. if (section.is_timedelta)
  274. {
  275. any_timedelta = true;
  276. }
  277. }
  278. return any_datetime && !any_timedelta;
  279. }
  280. std::string number_format::format(const std::string &text) const
  281. {
  282. return detail::number_formatter(format_string_, calendar::windows_1900).format_text(text);
  283. }
  284. std::string number_format::format(double number, calendar base_date) const
  285. {
  286. return detail::number_formatter(format_string_, base_date).format_number(number);
  287. }
  288. bool number_format::operator==(const number_format &other) const
  289. {
  290. return format_string_ == other.format_string_;
  291. }
  292. bool number_format::operator!=(const number_format &other) const
  293. {
  294. return !(*this == other);
  295. }
  296. } // namespace xlnt