Vince's CSV Parser
Loading...
Searching...
No Matches
csv_row_json.cpp
Go to the documentation of this file.
1
5#include "csv_row.hpp"
6
7namespace csv {
8 /*
9 The implementations for json_extra_space() and json_escape_string()
10 were modified from source code for JSON for Modern C++.
11
12 The respective license is below:
13
14 The code is licensed under the [MIT
15 License](http://opensource.org/licenses/MIT):
16
17 Copyright © 2013-2015 Niels Lohmann.
18
19 Permission is hereby granted, free of charge, to any person
20 obtaining a copy of this software and associated documentation files
21 (the "Software"), to deal in the Software without restriction,
22 including without limitation the rights to use, copy, modify, merge,
23 publish, distribute, sublicense, and/or sell copies of the Software,
24 and to permit persons to whom the Software is furnished to do so,
25 subject to the following conditions:
26
27 The above copyright notice and this permission notice shall be
28 included in all copies or substantial portions of the Software.
29
30 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
34 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
35 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 SOFTWARE.
38 */
39
40 namespace internals {
49 static std::size_t json_extra_space(csv::string_view& s) noexcept
50 {
51 std::size_t result = 0;
52
53
54 for (const auto& c : s)
55 {
56 switch (c)
57 {
58 case '"':
59 case '\\':
60 case '\b':
61 case '\f':
62 case '\n':
63 case '\r':
64 case '\t':
65 {
66 // from c (1 byte) to \x (2 bytes)
67 result += 1;
68 break;
69 }
70
71
72 default:
73 {
74 if (c >= 0x00 && c <= 0x1f)
75 {
76 // from c (1 byte) to \uxxxx (6 bytes)
77 result += 5;
78 }
79 break;
80 }
81 }
82 }
83
84
85 return result;
86 }
87
88 CSV_INLINE std::string json_escape_string(csv::string_view s) noexcept
89 {
90 const auto space = json_extra_space(s);
91 if (space == 0)
92 {
93 return std::string(s);
94 }
95
96 // create a result string of necessary size
97 size_t result_size = s.size() + space;
98 std::string result(result_size, '\\');
99 std::size_t pos = 0;
100
101 for (const auto& c : s)
102 {
103 switch (c)
104 {
105 // quotation mark (0x22)
106 case '"':
107 {
108 result[pos + 1] = '"';
109 pos += 2;
110 break;
111 }
112
113
114 // reverse solidus (0x5c)
115 case '\\':
116 {
117 // nothing to change
118 pos += 2;
119 break;
120 }
121
122
123 // backspace (0x08)
124 case '\b':
125 {
126 result[pos + 1] = 'b';
127 pos += 2;
128 break;
129 }
130
131
132 // formfeed (0x0c)
133 case '\f':
134 {
135 result[pos + 1] = 'f';
136 pos += 2;
137 break;
138 }
139
140
141 // newline (0x0a)
142 case '\n':
143 {
144 result[pos + 1] = 'n';
145 pos += 2;
146 break;
147 }
148
149
150 // carriage return (0x0d)
151 case '\r':
152 {
153 result[pos + 1] = 'r';
154 pos += 2;
155 break;
156 }
157
158
159 // horizontal tab (0x09)
160 case '\t':
161 {
162 result[pos + 1] = 't';
163 pos += 2;
164 break;
165 }
166
167
168 default:
169 {
170 if (c >= 0x00 && c <= 0x1f)
171 {
172 // print character c as \uxxxx
173 snprintf(&result[pos + 1], result_size - pos - 1, "u%04x", int(c));
174 pos += 6;
175 // overwrite trailing null character
176 result[pos] = '\\';
177 }
178 else
179 {
180 // all other characters are added as-is
181 result[pos++] = c;
182 }
183 break;
184 }
185 }
186 }
187
188 return result;
189 }
190 }
191
199 CSV_INLINE std::string CSVRow::to_json(const std::vector<std::string>& subset) const {
200 std::vector<std::string> col_names = subset;
201 if (subset.empty()) {
202 col_names = this->data ? this->get_col_names() : std::vector<std::string>({});
203 }
204
205 const size_t _n_cols = col_names.size();
206 std::string ret = "{";
207
208 for (size_t i = 0; i < _n_cols; i++) {
209 auto& col = col_names[i];
210 auto field = this->operator[](col);
211
212 // TODO: Possible performance enhancements by caching escaped column names
213 ret += '"' + internals::json_escape_string(col) + "\":";
214
215 // Add quotes around strings but not numbers
216 if (field.is_num())
217 ret += internals::json_escape_string(field.get<csv::string_view>());
218 else
219 ret += '"' + internals::json_escape_string(field.get<csv::string_view>()) + '"';
220
221 // Do not add comma after last string
222 if (i + 1 < _n_cols)
223 ret += ',';
224 }
225
226 ret += '}';
227 return ret;
228 }
229
237 CSV_INLINE std::string CSVRow::to_json_array(const std::vector<std::string>& subset) const {
238 std::vector<std::string> col_names = subset;
239 if (subset.empty())
240 col_names = this->data ? this->get_col_names() : std::vector<std::string>({});
241
242 const size_t _n_cols = col_names.size();
243 std::string ret = "[";
244
245 for (size_t i = 0; i < _n_cols; i++) {
246 auto field = this->operator[](col_names[i]);
247
248 // Add quotes around strings but not numbers
249 if (field.is_num())
250 ret += internals::json_escape_string(field.get<csv::string_view>());
251 else
252 ret += '"' + internals::json_escape_string(field.get<csv::string_view>()) + '"';
253
254 // Do not add comma after last string
255 if (i + 1 < _n_cols)
256 ret += ',';
257 }
258
259 ret += ']';
260 return ret;
261 }
262}
std::string to_json(const std::vector< std::string > &subset={}) const
Convert a CSV row to a JSON object, i.e.
std::string to_json_array(const std::vector< std::string > &subset={}) const
Convert a CSV row to a JSON array, i.e.
std::vector< std::string > get_col_names() const
Retrieve this row's associated column names.
Definition csv_row.hpp:307
CSVField operator[](size_t n) const
Return a CSVField object corrsponding to the nth value in the row.
Definition csv_row.cpp:20
#define CSV_INLINE
Helper macro which should be #defined as "inline" in the single header version.
Definition common.hpp:26
Defines the data type used for storing information about a CSV row.
CSV_CONST CONSTEXPR_17 OutArray arrayToDefault(T &&value)
Helper constexpr function to initialize an array with all the elements set to value.
The all encompassing namespace.
nonstd::string_view string_view
The string_view class used by this library.
Definition common.hpp:99