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 {
46 static std::size_t json_extra_space(csv::string_view& s) noexcept
47 {
48 std::size_t result = 0;
49
50
51 for (const auto& c : s)
52 {
53 switch (c)
54 {
55 case '"':
56 case '\\':
57 case '\b':
58 case '\f':
59 case '\n':
60 case '\r':
61 case '\t':
62 {
63 // from c (1 byte) to \x (2 bytes)
64 result += 1;
65 break;
66 }
67
68
69 default:
70 {
71 if (c >= 0x00 && c <= 0x1f)
72 {
73 // from c (1 byte) to \uxxxx (6 bytes)
74 result += 5;
75 }
76 break;
77 }
78 }
79 }
80
81
82 return result;
83 }
84
85 CSV_INLINE std::string json_escape_string(csv::string_view s) noexcept
86 {
87 const auto space = json_extra_space(s);
88 if (space == 0)
89 {
90 return std::string(s);
91 }
92
93 // create a result string of necessary size
94 size_t result_size = s.size() + space;
95 std::string result(result_size, '\\');
96 std::size_t pos = 0;
97
98 for (const auto& c : s)
99 {
100 switch (c)
101 {
102 // quotation mark (0x22)
103 case '"':
104 {
105 result[pos + 1] = '"';
106 pos += 2;
107 break;
108 }
109
110
111 // reverse solidus (0x5c)
112 case '\\':
113 {
114 // nothing to change
115 pos += 2;
116 break;
117 }
118
119
120 // backspace (0x08)
121 case '\b':
122 {
123 result[pos + 1] = 'b';
124 pos += 2;
125 break;
126 }
127
128
129 // formfeed (0x0c)
130 case '\f':
131 {
132 result[pos + 1] = 'f';
133 pos += 2;
134 break;
135 }
136
137
138 // newline (0x0a)
139 case '\n':
140 {
141 result[pos + 1] = 'n';
142 pos += 2;
143 break;
144 }
145
146
147 // carriage return (0x0d)
148 case '\r':
149 {
150 result[pos + 1] = 'r';
151 pos += 2;
152 break;
153 }
154
155
156 // horizontal tab (0x09)
157 case '\t':
158 {
159 result[pos + 1] = 't';
160 pos += 2;
161 break;
162 }
163
164
165 default:
166 {
167 if (c >= 0x00 && c <= 0x1f)
168 {
169 // print character c as \uxxxx
170 snprintf(&result[pos + 1], result_size - pos - 1, "u%04x", int(c));
171 pos += 6;
172 // overwrite trailing null character
173 result[pos] = '\\';
174 }
175 else
176 {
177 // all other characters are added as-is
178 result[pos++] = c;
179 }
180 break;
181 }
182 }
183 }
184
185 return result;
186 }
187 }
188
195 CSV_INLINE std::string CSVRow::to_json(const std::vector<std::string>& subset) const {
196 std::vector<std::string> col_names = subset;
197 if (subset.empty()) {
198 col_names = this->data ? this->get_col_names() : std::vector<std::string>({});
199 }
200
201 const size_t _n_cols = col_names.size();
202 std::string ret = "{";
203
204 for (size_t i = 0; i < _n_cols; i++) {
205 auto& col = col_names[i];
206 auto field = this->operator[](col);
207
208 // TODO: Possible performance enhancements by caching escaped column names
209 ret += '"' + internals::json_escape_string(col) + "\":";
210
211 // Add quotes around strings but not numbers
212 if (field.is_num())
213 ret += internals::json_escape_string(field.get<csv::string_view>());
214 else
215 ret += '"' + internals::json_escape_string(field.get<csv::string_view>()) + '"';
216
217 // Do not add comma after last string
218 if (i + 1 < _n_cols)
219 ret += ',';
220 }
221
222 ret += '}';
223 return ret;
224 }
225
232 CSV_INLINE std::string CSVRow::to_json_array(const std::vector<std::string>& subset) const {
233 std::vector<std::string> col_names = subset;
234 if (subset.empty())
235 col_names = this->data ? this->get_col_names() : std::vector<std::string>({});
236
237 const size_t _n_cols = col_names.size();
238 std::string ret = "[";
239
240 for (size_t i = 0; i < _n_cols; i++) {
241 auto field = this->operator[](col_names[i]);
242
243 // Add quotes around strings but not numbers
244 if (field.is_num())
245 ret += internals::json_escape_string(field.get<csv::string_view>());
246 else
247 ret += '"' + internals::json_escape_string(field.get<csv::string_view>()) + '"';
248
249 // Do not add comma after last string
250 if (i + 1 < _n_cols)
251 ret += ',';
252 }
253
254 ret += ']';
255 return ret;
256 }
257}
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:291
CSVField operator[](size_t n) const
Return a CSVField object corrsponding to the nth value in the row.
Definition csv_row.cpp:37
#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.
The all encompassing namespace.
nonstd::string_view string_view
The string_view class used by this library.
Definition common.hpp:135