cell_reference.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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 <cctype>
  25. #include <xlnt/cell/cell_reference.hpp>
  26. #include <xlnt/utils/exceptions.hpp>
  27. #include <xlnt/worksheet/range_reference.hpp>
  28. #include <detail/constants.hpp>
  29. namespace xlnt {
  30. std::size_t cell_reference_hash::operator()(const cell_reference &k) const
  31. {
  32. return k.row() * constants::max_column().index + k.column_index();
  33. }
  34. cell_reference &cell_reference::make_absolute(bool absolute_column, bool absolute_row)
  35. {
  36. column_absolute(absolute_column);
  37. row_absolute(absolute_row);
  38. return *this;
  39. }
  40. cell_reference::cell_reference()
  41. : cell_reference(1, 1)
  42. {
  43. }
  44. cell_reference::cell_reference(const std::string &string)
  45. {
  46. auto split = split_reference(string, absolute_column_, absolute_row_);
  47. column(split.first);
  48. row(split.second);
  49. }
  50. cell_reference::cell_reference(const char *reference_string)
  51. : cell_reference(std::string(reference_string))
  52. {
  53. }
  54. cell_reference::cell_reference(column_t column_index, row_t row)
  55. : column_(column_index), row_(row), absolute_row_(false), absolute_column_(false)
  56. {
  57. if (row_ == 0
  58. || column_ == 0
  59. || !(row_ <= constants::max_row())
  60. || !(column_ <= constants::max_column()))
  61. {
  62. throw invalid_cell_reference(column_, row_);
  63. }
  64. }
  65. range_reference cell_reference::operator,(const xlnt::cell_reference &other) const
  66. {
  67. return range_reference(*this, other);
  68. }
  69. std::string cell_reference::to_string() const
  70. {
  71. std::string string_representation;
  72. if (absolute_column_)
  73. {
  74. string_representation.append("$");
  75. }
  76. string_representation.append(column_.column_string());
  77. if (absolute_row_)
  78. {
  79. string_representation.append("$");
  80. }
  81. string_representation.append(std::to_string(row_));
  82. return string_representation;
  83. }
  84. range_reference cell_reference::to_range() const
  85. {
  86. return range_reference(column_, row_, column_, row_);
  87. }
  88. std::pair<std::string, row_t> cell_reference::split_reference(const std::string &reference_string)
  89. {
  90. bool ignore1, ignore2;
  91. return split_reference(reference_string, ignore1, ignore2);
  92. }
  93. std::pair<std::string, row_t> cell_reference::split_reference(
  94. const std::string &reference_string, bool &absolute_column, bool &absolute_row)
  95. {
  96. absolute_column = false;
  97. absolute_row = false;
  98. // Convert a coordinate string like 'B12' to a tuple ('B', 12)
  99. bool column_part = true;
  100. std::string column_string;
  101. for (auto character : reference_string)
  102. {
  103. auto upper = static_cast<char>(std::toupper(static_cast<std::uint8_t>(character)));
  104. if (std::isalpha(character))
  105. {
  106. if (column_part)
  107. {
  108. column_string.append(1, upper);
  109. }
  110. else
  111. {
  112. throw invalid_cell_reference(reference_string);
  113. }
  114. }
  115. else if (character == '$')
  116. {
  117. if (column_part)
  118. {
  119. if (column_string.empty())
  120. {
  121. column_string.append(1, upper);
  122. }
  123. else
  124. {
  125. column_part = false;
  126. }
  127. }
  128. }
  129. else
  130. {
  131. if (column_part)
  132. {
  133. column_part = false;
  134. }
  135. else if (!std::isdigit(character))
  136. {
  137. throw invalid_cell_reference(reference_string);
  138. }
  139. }
  140. }
  141. std::string row_string = reference_string.substr(column_string.length());
  142. if (row_string.length() == 0)
  143. {
  144. throw invalid_cell_reference(reference_string);
  145. }
  146. if (column_string[0] == '$')
  147. {
  148. absolute_column = true;
  149. column_string = column_string.substr(1);
  150. }
  151. if (row_string[0] == '$')
  152. {
  153. absolute_row = true;
  154. row_string = row_string.substr(1);
  155. }
  156. return {column_string, std::stoi(row_string)};
  157. }
  158. bool cell_reference::column_absolute() const
  159. {
  160. return absolute_column_;
  161. }
  162. void cell_reference::column_absolute(bool absolute_column)
  163. {
  164. absolute_column_ = absolute_column;
  165. }
  166. bool cell_reference::row_absolute() const
  167. {
  168. return absolute_row_;
  169. }
  170. void cell_reference::row_absolute(bool absolute_row)
  171. {
  172. absolute_row_ = absolute_row;
  173. }
  174. column_t cell_reference::column() const
  175. {
  176. return column_;
  177. }
  178. void cell_reference::column(const std::string &column_string)
  179. {
  180. column_ = column_t(column_string);
  181. }
  182. column_t::index_t cell_reference::column_index() const
  183. {
  184. return column_.index;
  185. }
  186. void cell_reference::column_index(column_t column)
  187. {
  188. column_ = column;
  189. }
  190. row_t cell_reference::row() const
  191. {
  192. return row_;
  193. }
  194. void cell_reference::row(row_t row)
  195. {
  196. row_ = row;
  197. }
  198. bool cell_reference::operator==(const std::string &reference_string) const
  199. {
  200. return *this == cell_reference(reference_string);
  201. }
  202. bool cell_reference::operator==(const char *reference_string) const
  203. {
  204. return *this == std::string(reference_string);
  205. }
  206. bool cell_reference::operator!=(const cell_reference &comparand) const
  207. {
  208. return !(*this == comparand);
  209. }
  210. bool cell_reference::operator!=(const std::string &reference_string) const
  211. {
  212. return *this != cell_reference(reference_string);
  213. }
  214. bool cell_reference::operator!=(const char *reference_string) const
  215. {
  216. return *this != std::string(reference_string);
  217. }
  218. cell_reference cell_reference::make_offset(int column_offset, int row_offset) const
  219. {
  220. // TODO: check for overflow/underflow
  221. auto relative_column = static_cast<column_t::index_t>(static_cast<int>(column_.index) + column_offset);
  222. auto relative_row = static_cast<row_t>(static_cast<int>(row_) + row_offset);
  223. return cell_reference(relative_column, relative_row);
  224. }
  225. bool cell_reference::operator==(const cell_reference &comparand) const
  226. {
  227. return comparand.column_ == column_
  228. && comparand.row_ == row_
  229. && absolute_column_ == comparand.absolute_column_
  230. && absolute_row_ == comparand.absolute_row_;
  231. }
  232. } // namespace xlnt