mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
scan and replace '.' with ',' when decimal separator is comma
This commit is contained in:
parent
2eb88c23d6
commit
d69a5dea75
|
@ -28,6 +28,7 @@
|
|||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace xlnt {
|
||||
namespace detail {
|
||||
|
@ -115,5 +116,46 @@ bool float_equals(const LNumber &lhs, const RNumber &rhs,
|
|||
return ((lhs + scaled_fuzz) >= rhs) && ((rhs + scaled_fuzz) >= lhs);
|
||||
}
|
||||
|
||||
struct number_converter
|
||||
{
|
||||
explicit number_converter()
|
||||
: should_convert_to_comma(std::use_facet<std::numpunct<char>>(std::locale{}).decimal_point() == ',')
|
||||
{
|
||||
}
|
||||
|
||||
double stold(std::string &s) const noexcept
|
||||
{
|
||||
assert(!s.empty());
|
||||
if (should_convert_to_comma)
|
||||
{
|
||||
auto decimal_pt = std::find(s.begin(), s.end(), '.');
|
||||
if (decimal_pt != s.end())
|
||||
{
|
||||
*decimal_pt = ',';
|
||||
}
|
||||
}
|
||||
return strtod(s.c_str(), nullptr);
|
||||
}
|
||||
|
||||
double stold(const std::string &s) const
|
||||
{
|
||||
assert(!s.empty());
|
||||
if (!should_convert_to_comma)
|
||||
{
|
||||
return strtod(s.c_str(), nullptr);
|
||||
}
|
||||
std::string copy(s);
|
||||
auto decimal_pt = std::find(copy.begin(), copy.end(), '.');
|
||||
if (decimal_pt != s.end())
|
||||
{
|
||||
*decimal_pt = ',';
|
||||
}
|
||||
return strtod(copy.c_str(), nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
bool should_convert_to_comma = false;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -116,84 +116,6 @@ bool is_true(const std::string &bool_string)
|
|||
#endif
|
||||
}
|
||||
|
||||
// can find documentation for _strtod_l back to VS 2015
|
||||
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strtod-strtod-l-wcstod-wcstod-l?view=vs-2015
|
||||
//
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Cache locale object
|
||||
static int c_locale_initialized = 0;
|
||||
static _locale_t c_locale;
|
||||
|
||||
_locale_t get_c_locale()
|
||||
{
|
||||
if (!c_locale_initialized)
|
||||
{
|
||||
c_locale_initialized = 1;
|
||||
c_locale = _create_locale(LC_ALL, "C");
|
||||
}
|
||||
return c_locale;
|
||||
}
|
||||
|
||||
struct number_converter
|
||||
{
|
||||
double stold(const std::string &s)
|
||||
{
|
||||
return _strtod_l(s.c_str(), nullptr, get_c_locale());
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
// according to various sources, something like the below *would* work for POSIX systems
|
||||
// however due to uncertainty on whether it will actually work it is not used
|
||||
//#include <stdlib.h>
|
||||
//#include <xlocale.h>
|
||||
//
|
||||
//// Cache locale object
|
||||
//static int c_locale_initialized = 0;
|
||||
//static locale_t c_locale;
|
||||
//
|
||||
//locale_t get_c_locale()
|
||||
//{
|
||||
// if (!c_locale_initialized)
|
||||
// {
|
||||
// c_locale_initialized = 1;
|
||||
// c_locale = newlocale(LC_ALL_MASK, "C", NULL);
|
||||
// }
|
||||
// return c_locale;
|
||||
//}
|
||||
//
|
||||
//double strtod_c(const char *nptr, char **endptr)
|
||||
//{
|
||||
// return strtod_l(nptr, endptr, get_c_locale());
|
||||
//}
|
||||
|
||||
// add specialisations whenever possible
|
||||
// in the spreadsheet-load benchmark, strtod is roughly 10% faster
|
||||
struct number_converter
|
||||
{
|
||||
number_converter()
|
||||
{
|
||||
stream.imbue(std::locale("C"));
|
||||
}
|
||||
|
||||
double stold(const std::string &s)
|
||||
{
|
||||
stream.str(s);
|
||||
stream.clear();
|
||||
stream >> result;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::istringstream stream;
|
||||
double result;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
using style_id_pair = std::pair<xlnt::detail::style_impl, std::size_t>;
|
||||
|
||||
|
@ -388,14 +310,14 @@ Cell parse_cell(xlnt::row_t row_arg, xml::parser *parser)
|
|||
}
|
||||
|
||||
// <row> inside <sheetData> element
|
||||
std::pair<xlnt::row_properties, int> parse_row(xml::parser *parser, number_converter &converter, std::vector<Cell> &parsed_cells)
|
||||
std::pair<xlnt::row_properties, int> parse_row(xml::parser *parser, xlnt::detail::number_converter &converter, std::vector<Cell> &parsed_cells)
|
||||
{
|
||||
std::pair<xlnt::row_properties, int> props;
|
||||
for (auto &attr : parser->attribute_map())
|
||||
{
|
||||
if (string_equal(attr.first.name(), "dyDescent"))
|
||||
{
|
||||
props.first.dy_descent = converter.stold(attr.second.value.c_str());
|
||||
props.first.dy_descent = converter.stold(attr.second.value);
|
||||
}
|
||||
else if (string_equal(attr.first.name(), "spans"))
|
||||
{
|
||||
|
@ -403,7 +325,7 @@ std::pair<xlnt::row_properties, int> parse_row(xml::parser *parser, number_conve
|
|||
}
|
||||
else if (string_equal(attr.first.name(), "ht"))
|
||||
{
|
||||
props.first.height = converter.stold(attr.second.value.c_str());
|
||||
props.first.height = converter.stold(attr.second.value);
|
||||
}
|
||||
else if (string_equal(attr.first.name(), "s"))
|
||||
{
|
||||
|
@ -467,7 +389,7 @@ std::pair<xlnt::row_properties, int> parse_row(xml::parser *parser, number_conve
|
|||
}
|
||||
|
||||
// <sheetData> inside <worksheet> element
|
||||
Sheet_Data parse_sheet_data(xml::parser *parser, number_converter &converter)
|
||||
Sheet_Data parse_sheet_data(xml::parser *parser, xlnt::detail::number_converter &converter)
|
||||
{
|
||||
Sheet_Data sheet_data;
|
||||
int level = 1; // nesting level
|
||||
|
@ -1091,7 +1013,7 @@ void xlsx_consumer::read_worksheet_sheetdata()
|
|||
}
|
||||
case cell::type::number:
|
||||
{
|
||||
ws_cell_impl->value_numeric_ = converter.stold(cell.value.c_str());
|
||||
ws_cell_impl->value_numeric_ = converter.stold(cell.value);
|
||||
break;
|
||||
}
|
||||
case cell::type::shared_string:
|
||||
|
|
Loading…
Reference in New Issue
Block a user