begin synchronizing tests with openpyxl 2.4 branch, fix type guessing logic

This commit is contained in:
Thomas Fussell 2015-10-01 23:09:25 -04:00
parent 6d39ac1d31
commit c03f7d28e4
3 changed files with 168 additions and 96 deletions

View File

@ -61,10 +61,6 @@ class cell
public:
static const std::unordered_map<std::string, int> ErrorCodes;
static std::string check_string(const std::string &value);
static std::string check_numeric(const std::string &value);
static std::string check_error(const std::string &value);
cell();
cell(worksheet ws, const cell_reference &reference);
cell(worksheet ws, const cell_reference &reference, const value &initial_value);

View File

@ -161,49 +161,134 @@ void cell::set_value(const value &v)
d_->value_ = v;
}
// return s after checking encoding, size, and illegal characters
std::string check_string(std::string s)
{
if (s.size() == 0)
{
return s;
}
// check encoding?
if (s.size() > 32767)
{
s = s.substr(0, 32767); // max string length in Excel
}
for (unsigned char c : s)
{
if (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31))
{
throw "illegal characters";
}
}
return s;
}
std::pair<bool, long double> cast_numeric(const std::string &s)
{
const char *str = s.c_str();
char *str_end = nullptr;
auto result = std::strtold(str, &str_end);
if (str_end != str + s.size()) return{ false, 0 };
return{ true, result };
}
std::pair<bool, long double> cast_percentage(const std::string &s)
{
if (s.back() == '%')
{
auto number = cast_numeric(s.substr(0, s.size() - 1));
if (number.first)
{
return{ true, number.second / 100 };
}
}
return { false, 0 };
}
std::pair<bool, time> cast_time(const std::string &s)
{
time result;
try
{
auto last_colon = s.find_last_of(':');
if (last_colon == std::string::npos) return { false, result };
double seconds = std::stod(s.substr(last_colon + 1));
result.second = static_cast<int>(seconds);
result.microsecond = static_cast<int>((seconds - static_cast<double>(result.second)) * 1e6);
auto first_colon = s.find_first_of(':');
if (first_colon == last_colon)
{
auto decimal_pos = s.find('.');
if (decimal_pos != std::string::npos)
{
result.minute = std::stoi(s.substr(0, first_colon));
}
else
{
result.hour = std::stoi(s.substr(0, first_colon));
result.minute = result.second;
result.second = 0;
}
}
else
{
result.hour = std::stoi(s.substr(0, first_colon));
result.minute = std::stoi(s.substr(first_colon + 1, last_colon - first_colon - 1));
}
}
catch (std::invalid_argument)
{
return{ false, result };
}
return { true, result };
}
void cell::set_value(const std::string &s)
{
if(!get_parent().get_parent().get_guess_types())
{
d_->is_date_ = false;
d_->value_ = value(s);
}
else
{
d_->is_date_ = false;
d_->is_date_ = false;
auto temp = check_string(s);
d_->value_ = value(temp);
switch(data_type_for_value(s))
{
case value::type::numeric:
if(s.find(':') != std::string::npos)
{
d_->is_date_ = true;
d_->value_ = value(time(s).to_number());
}
else if(s.back() == '%')
{
d_->value_ = value(std::stod(s.substr(0, s.length() - 1)) / 100);
get_style().get_number_format().set_format_code(xlnt::number_format::format::percentage);
}
else
{
d_->value_ = value(std::stod(s));
}
break;
case value::type::boolean:
d_->value_ = value(s == "TRUE" || s == "true");
break;
case value::type::error:
d_->value_ = value(s);
break;
case value::type::string:
d_->value_ = value(s);
break;
case value::type::null:
d_->value_ = value::null();
break;
default: throw data_type_exception();
}
if (temp.size() > 1 && temp.front() == '=')
{
d_->formula_ = temp;
}
if(get_parent().get_parent().get_guess_types())
{
auto percentage = cast_percentage(s);
if (percentage.first)
{
d_->value_ = value(percentage.second);
get_style().get_number_format().set_format_code(xlnt::number_format::format::percentage);
}
else
{
auto time = cast_time(s);
if (time.first)
{
set_value(time.second);
}
else
{
auto numeric = cast_numeric(s);
if (numeric.first)
{
d_->value_ = value(numeric.second);
}
}
}
}
}

View File

@ -9,6 +9,49 @@
class test_cell : public CxxTest::TestSuite
{
public:
void test_infer_numeric()
{
wb.set_guess_types(true);
xlnt::worksheet ws = wb.create_sheet();
xlnt::cell cell(ws, "A1");
cell.set_value("4.2");
TS_ASSERT(cell.get_value() == 4.2);
cell.set_value("-42.000");
TS_ASSERT(cell.get_value() == -42);
cell.set_value("0");
TS_ASSERT(cell.get_value() == 0);
cell.set_value("0.9999");
TS_ASSERT(cell.get_value() == 0.9999);
cell.set_value("99E-02");
TS_ASSERT(cell.get_value() == 0.99);
cell.set_value("4");
TS_ASSERT(cell.get_value() == 4);
cell.set_value("-1E3");
TS_ASSERT(cell.get_value() == -1000);
cell.set_value("2e+2");
TS_ASSERT(cell.get_value() == 200);
cell.set_value("3.1%");
TS_ASSERT(cell.get_value() == 0.031);
cell.set_value("03:40:16");
TS_ASSERT(cell.get_value() == xlnt::time(3, 40, 16));
cell.set_value("03:40");
TS_ASSERT(cell.get_value() == xlnt::time(3, 40));
cell.set_value("30:33.865633336");
TS_ASSERT(cell.get_value() == xlnt::time(0, 30, 33, 865633));
}
void test_coordinates()
{
xlnt::cell_reference coord("ZF46");
@ -120,50 +163,6 @@ public:
TS_ASSERT(cell.get_value().is(xlnt::value::type::null));
}
void test_numeric()
{
xlnt::workbook wb_guess_types;
wb.set_guess_types(true);
xlnt::worksheet ws = wb.create_sheet();
xlnt::cell cell(ws, "A1");
cell.set_value(42);
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value("4.2");
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value("-42.000");
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value("0");
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value(0);
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value(0.0001);
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value("0.9999");
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value("99E-02");
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value(1e1);
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value("4");
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value("-1E3");
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
cell.set_value(4);
TS_ASSERT(cell.get_value().is(xlnt::value::type::numeric));
}
void test_string()
{
xlnt::worksheet ws = wb.create_sheet();
@ -203,14 +202,6 @@ public:
TS_ASSERT(cell.get_value().is(xlnt::value::type::boolean));
}
void test_leading_zero()
{
xlnt::worksheet ws = wb.create_sheet();
xlnt::cell cell(ws, "A1");
cell.set_value("0800");
TS_ASSERT(cell.get_value().is(xlnt::value::type::string));
}
void test_error_codes()
{
xlnt::worksheet ws = wb.create_sheet();