Skip to content

Commit

Permalink
CSVField: new member function try_parse_decimal() to specify one or m…
Browse files Browse the repository at this point in the history
…ore 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
  • Loading branch information
wilfz authored Jun 6, 2024
1 parent 2607ee0 commit d76acaf
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 20 deletions.
23 changes: 23 additions & 0 deletions include/internal/csv_row.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,29 @@ namespace csv {
return true;
}

// try_parse_decimal uses the specified decimal symbol and
// also sets the private members _type and value
CSV_INLINE bool CSVField::try_parse_decimal(long double& dVal, const char decimalsymbol) {
// If field has already been parsed to empty, no need to do it aagin:
if (this->_type == DataType::CSV_NULL)
return false;

// Not yet parsed or possibly parsed with other decimalsymbol
if (this->_type == DataType::UNKNOWN || this->_type == DataType::CSV_STRING || this->_type == DataType::CSV_DOUBLE)
this->_type = internals::data_type(this->sv, &this->value, decimalsymbol); // parse again

// Integral types are not affected by decimalsymbol and need not be parsed again

// Either we already had an integral type before, or we we just got any numeric type now.
if (this->_type >= DataType::CSV_INT8 && this->_type <= DataType::CSV_DOUBLE) {
dVal = this->value;
return true;
}

// CSV_NULL or CSV_STRING, not numeric
return false;
}

#ifdef _MSC_VER
#pragma region CSVRow Iterator
#endif
Expand Down
6 changes: 6 additions & 0 deletions include/internal/csv_row.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ namespace csv {
/** Parse a hexadecimal value, returning false if the value is not hex. */
bool try_parse_hex(int& parsedValue);

/** Parse a value, returning false if the value is not decimal.
* If true it also sets the private members _type and value.
* Decimal symbol may be given explicitly, default is '.'.
*/
bool try_parse_decimal(long double& dVal, const char decimalsymbol = '.');

/** Compares the contents of this field to a numeric value. If this
* field does not contain a numeric value, then all comparisons return
* false.
Expand Down
22 changes: 12 additions & 10 deletions include/internal/data_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ namespace csv {
template<> inline DataType type_num<std::nullptr_t>() { return DataType::CSV_NULL; }
template<> inline DataType type_num<std::string>() { return DataType::CSV_STRING; }

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

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

is_negative = true;
break;
case '.':
if (!dot_allowed) {
return DataType::CSV_STRING;
}

dot_allowed = false;
prob_float = true;
break;
// case decimalsymbol: not allowed because decimalsymbol is not a literal,
// it is handled in the default block
case 'e':
case 'E':
// Process scientific notation
Expand Down Expand Up @@ -328,6 +325,11 @@ namespace csv {
else
integral_part = (integral_part * 10) + digit;
}
// case decimalymbol: not allowed because decimalsymbol is not a literal.
else if (dot_allowed && current == decimalsymbol) {
dot_allowed = false;
prob_float = true;
}
else {
return DataType::CSV_STRING;
}
Expand Down
51 changes: 41 additions & 10 deletions single_include/csv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5151,7 +5151,8 @@ namespace csv {
template<> inline DataType type_num<std::nullptr_t>() { return DataType::CSV_NULL; }
template<> inline DataType type_num<std::string>() { return DataType::CSV_STRING; }

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

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

is_negative = true;
break;
case '.':
if (!dot_allowed) {
return DataType::CSV_STRING;
}

dot_allowed = false;
prob_float = true;
break;
// case decimalsymbol: not allowed because decimalsymbol is not a literal,
// it is handled in the default block
case 'e':
case 'E':
// Process scientific notation
Expand Down Expand Up @@ -5388,6 +5385,11 @@ namespace csv {
else
integral_part = (integral_part * 10) + digit;
}
// case decimalymbol: not allowed because decimalsymbol is not a literal.
else if (dot_allowed && current == decimalsymbol) {
dot_allowed = false;
prob_float = true;
}
else {
return DataType::CSV_STRING;
}
Expand Down Expand Up @@ -5610,6 +5612,12 @@ namespace csv {
/** Parse a hexadecimal value, returning false if the value is not hex. */
bool try_parse_hex(int& parsedValue);

/** Parse a value, returning false if the value is not decimal.
* If true it also sets the private members _type and value.
* Decimal symbol may be given explicitly, default is '.'.
*/
bool try_parse_decimal(long double& dVal, const char decimalsymbol = '.');

/** Compares the contents of this field to a numeric value. If this
* field does not contain a numeric value, then all comparisons return
* false.
Expand Down Expand Up @@ -7847,6 +7855,29 @@ namespace csv {
return true;
}

// try_parse_decimal uses the specified decimal symbol and
// also sets the private members _type and value
CSV_INLINE bool CSVField::try_parse_decimal(long double& dVal, const char decimalsymbol) {
// If field has already been parsed to empty, no need to do it aagin:
if (this->_type == DataType::CSV_NULL)
return false;

// Not yet parsed or possibly parsed with other decimalsymbol
if (this->_type == DataType::UNKNOWN || this->_type == DataType::CSV_STRING || this->_type == DataType::CSV_DOUBLE)
this->_type = internals::data_type(this->sv, &this->value, decimalsymbol); // parse again

// Integral types are not affected by decimalsymbol and need not be parsed again

// Either we already had an integral type before, or we we just got any numeric type now.
if (this->_type >= DataType::CSV_INT8 && this->_type <= DataType::CSV_DOUBLE) {
dVal = this->value;
return true;
}

// CSV_NULL or CSV_STRING, not numeric
return false;
}

#ifdef _MSC_VER
#pragma region CSVRow Iterator
#endif
Expand Down

0 comments on commit d76acaf

Please sign in to comment.