Skip to content

Commit d76acaf

Browse files
authored
CSVField: new member function try_parse_decimal() to specify one or more decimal symbols (#226)
* CSVField: new member function try_parse_decimal() to specify one or more decimal symbols * merge from vincentlaucsb/csv-parser: add case '+' in try_parse_decimal(), too * reworked try_parse_decimal() according to Vincent La's suggestion
1 parent 2607ee0 commit d76acaf

File tree

4 files changed

+82
-20
lines changed

4 files changed

+82
-20
lines changed

include/internal/csv_row.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,29 @@ namespace csv {
164164
return true;
165165
}
166166

167+
// try_parse_decimal uses the specified decimal symbol and
168+
// also sets the private members _type and value
169+
CSV_INLINE bool CSVField::try_parse_decimal(long double& dVal, const char decimalsymbol) {
170+
// If field has already been parsed to empty, no need to do it aagin:
171+
if (this->_type == DataType::CSV_NULL)
172+
return false;
173+
174+
// Not yet parsed or possibly parsed with other decimalsymbol
175+
if (this->_type == DataType::UNKNOWN || this->_type == DataType::CSV_STRING || this->_type == DataType::CSV_DOUBLE)
176+
this->_type = internals::data_type(this->sv, &this->value, decimalsymbol); // parse again
177+
178+
// Integral types are not affected by decimalsymbol and need not be parsed again
179+
180+
// Either we already had an integral type before, or we we just got any numeric type now.
181+
if (this->_type >= DataType::CSV_INT8 && this->_type <= DataType::CSV_DOUBLE) {
182+
dVal = this->value;
183+
return true;
184+
}
185+
186+
// CSV_NULL or CSV_STRING, not numeric
187+
return false;
188+
}
189+
167190
#ifdef _MSC_VER
168191
#pragma region CSVRow Iterator
169192
#endif

include/internal/csv_row.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,12 @@ namespace csv {
217217
/** Parse a hexadecimal value, returning false if the value is not hex. */
218218
bool try_parse_hex(int& parsedValue);
219219

220+
/** Parse a value, returning false if the value is not decimal.
221+
* If true it also sets the private members _type and value.
222+
* Decimal symbol may be given explicitly, default is '.'.
223+
*/
224+
bool try_parse_decimal(long double& dVal, const char decimalsymbol = '.');
225+
220226
/** Compares the contents of this field to a numeric value. If this
221227
* field does not contain a numeric value, then all comparisons return
222228
* false.

include/internal/data_type.hpp

+12-10
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ namespace csv {
9191
template<> inline DataType type_num<std::nullptr_t>() { return DataType::CSV_NULL; }
9292
template<> inline DataType type_num<std::string>() { return DataType::CSV_STRING; }
9393

94-
CONSTEXPR_14 DataType data_type(csv::string_view in, long double* const out = nullptr);
94+
CONSTEXPR_14 DataType data_type(csv::string_view in, long double* const out = nullptr,
95+
const char decimalsymbol = '.');
9596
#endif
9697

9798
/** Given a byte size, return the largest number than can be stored in
@@ -234,9 +235,11 @@ namespace csv {
234235
* @param[in] in String value to be examined
235236
* @param[out] out Pointer to long double where results of numeric parsing
236237
* get stored
238+
* @param[in] decimalsymbol the character separating integral and decimal part,
239+
* defaults to '.' if omitted
237240
*/
238241
CONSTEXPR_14
239-
DataType data_type(csv::string_view in, long double* const out) {
242+
DataType data_type(csv::string_view in, long double* const out, const char decimalsymbol) {
240243
// Empty string --> NULL
241244
if (in.size() == 0)
242245
return DataType::CSV_NULL;
@@ -282,14 +285,8 @@ namespace csv {
282285

283286
is_negative = true;
284287
break;
285-
case '.':
286-
if (!dot_allowed) {
287-
return DataType::CSV_STRING;
288-
}
289-
290-
dot_allowed = false;
291-
prob_float = true;
292-
break;
288+
// case decimalsymbol: not allowed because decimalsymbol is not a literal,
289+
// it is handled in the default block
293290
case 'e':
294291
case 'E':
295292
// Process scientific notation
@@ -328,6 +325,11 @@ namespace csv {
328325
else
329326
integral_part = (integral_part * 10) + digit;
330327
}
328+
// case decimalymbol: not allowed because decimalsymbol is not a literal.
329+
else if (dot_allowed && current == decimalsymbol) {
330+
dot_allowed = false;
331+
prob_float = true;
332+
}
331333
else {
332334
return DataType::CSV_STRING;
333335
}

single_include/csv.hpp

+41-10
Original file line numberDiff line numberDiff line change
@@ -5151,7 +5151,8 @@ namespace csv {
51515151
template<> inline DataType type_num<std::nullptr_t>() { return DataType::CSV_NULL; }
51525152
template<> inline DataType type_num<std::string>() { return DataType::CSV_STRING; }
51535153

5154-
CONSTEXPR_14 DataType data_type(csv::string_view in, long double* const out = nullptr);
5154+
CONSTEXPR_14 DataType data_type(csv::string_view in, long double* const out = nullptr,
5155+
const char decimalsymbol = '.');
51555156
#endif
51565157

51575158
/** Given a byte size, return the largest number than can be stored in
@@ -5294,9 +5295,11 @@ namespace csv {
52945295
* @param[in] in String value to be examined
52955296
* @param[out] out Pointer to long double where results of numeric parsing
52965297
* get stored
5298+
* @param[in] decimalsymbol the character separating integral and decimal part,
5299+
* defaults to '.' if omitted
52975300
*/
52985301
CONSTEXPR_14
5299-
DataType data_type(csv::string_view in, long double* const out) {
5302+
DataType data_type(csv::string_view in, long double* const out, const char decimalsymbol) {
53005303
// Empty string --> NULL
53015304
if (in.size() == 0)
53025305
return DataType::CSV_NULL;
@@ -5342,14 +5345,8 @@ namespace csv {
53425345

53435346
is_negative = true;
53445347
break;
5345-
case '.':
5346-
if (!dot_allowed) {
5347-
return DataType::CSV_STRING;
5348-
}
5349-
5350-
dot_allowed = false;
5351-
prob_float = true;
5352-
break;
5348+
// case decimalsymbol: not allowed because decimalsymbol is not a literal,
5349+
// it is handled in the default block
53535350
case 'e':
53545351
case 'E':
53555352
// Process scientific notation
@@ -5388,6 +5385,11 @@ namespace csv {
53885385
else
53895386
integral_part = (integral_part * 10) + digit;
53905387
}
5388+
// case decimalymbol: not allowed because decimalsymbol is not a literal.
5389+
else if (dot_allowed && current == decimalsymbol) {
5390+
dot_allowed = false;
5391+
prob_float = true;
5392+
}
53915393
else {
53925394
return DataType::CSV_STRING;
53935395
}
@@ -5610,6 +5612,12 @@ namespace csv {
56105612
/** Parse a hexadecimal value, returning false if the value is not hex. */
56115613
bool try_parse_hex(int& parsedValue);
56125614

5615+
/** Parse a value, returning false if the value is not decimal.
5616+
* If true it also sets the private members _type and value.
5617+
* Decimal symbol may be given explicitly, default is '.'.
5618+
*/
5619+
bool try_parse_decimal(long double& dVal, const char decimalsymbol = '.');
5620+
56135621
/** Compares the contents of this field to a numeric value. If this
56145622
* field does not contain a numeric value, then all comparisons return
56155623
* false.
@@ -7847,6 +7855,29 @@ namespace csv {
78477855
return true;
78487856
}
78497857

7858+
// try_parse_decimal uses the specified decimal symbol and
7859+
// also sets the private members _type and value
7860+
CSV_INLINE bool CSVField::try_parse_decimal(long double& dVal, const char decimalsymbol) {
7861+
// If field has already been parsed to empty, no need to do it aagin:
7862+
if (this->_type == DataType::CSV_NULL)
7863+
return false;
7864+
7865+
// Not yet parsed or possibly parsed with other decimalsymbol
7866+
if (this->_type == DataType::UNKNOWN || this->_type == DataType::CSV_STRING || this->_type == DataType::CSV_DOUBLE)
7867+
this->_type = internals::data_type(this->sv, &this->value, decimalsymbol); // parse again
7868+
7869+
// Integral types are not affected by decimalsymbol and need not be parsed again
7870+
7871+
// Either we already had an integral type before, or we we just got any numeric type now.
7872+
if (this->_type >= DataType::CSV_INT8 && this->_type <= DataType::CSV_DOUBLE) {
7873+
dVal = this->value;
7874+
return true;
7875+
}
7876+
7877+
// CSV_NULL or CSV_STRING, not numeric
7878+
return false;
7879+
}
7880+
78507881
#ifdef _MSC_VER
78517882
#pragma region CSVRow Iterator
78527883
#endif

0 commit comments

Comments
 (0)