Skip to content

Commit 718e67b

Browse files
committed
fix #195: Fix string to double conversion (space before number)
1 parent 8b8167f commit 718e67b

File tree

2 files changed

+133
-39
lines changed

2 files changed

+133
-39
lines changed

include/scratchcpp/value.h

Lines changed: 100 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -257,24 +257,7 @@ class LIBSCRATCHCPP_EXPORT Value
257257
case Type::Integer:
258258
return std::to_string(m_intValue);
259259
case Type::Double: {
260-
std::stringstream stream;
261-
stream << m_doubleValue;
262-
std::string s = stream.str();
263-
std::size_t index;
264-
265-
for (int i = 0; i < 2; i++) {
266-
if (i == 0)
267-
index = s.find("e+");
268-
else
269-
index = s.find("e-");
270-
271-
if (index != std::string::npos) {
272-
while ((s.size() >= index + 3) && (s[index + 2] == '0'))
273-
s.erase(index + 2, 1);
274-
}
275-
}
276-
277-
return s;
260+
return doubleToString(m_doubleValue);
278261
}
279262
case Type::Bool:
280263
return m_boolValue ? "true" : "false";
@@ -471,6 +454,26 @@ class LIBSCRATCHCPP_EXPORT Value
471454
std::string m_stringValue;
472455
};
473456

457+
// -1 - error
458+
// 0 - is string
459+
// 1 - is long
460+
// 2 - is double
461+
static int checkString(const std::string &str, long *longValue, double *doubleValue)
462+
{
463+
if (!longValue || !doubleValue)
464+
return -1;
465+
466+
bool ok;
467+
468+
if ((str.find_first_of('.') == std::string::npos) && (str.find_first_of('e') == std::string::npos) && (str.find_first_of('E') == std::string::npos)) {
469+
*longValue = stringToLong(str, &ok);
470+
return ok ? 1 : 0;
471+
} else {
472+
*doubleValue = stringToDouble(str, &ok);
473+
return ok ? 2 : 0;
474+
}
475+
}
476+
474477
void initString(const std::string &str)
475478
{
476479
if (str.empty())
@@ -486,23 +489,21 @@ class LIBSCRATCHCPP_EXPORT Value
486489
return;
487490
}
488491

489-
bool ok;
490-
bool isLong = false;
491492
long l;
492493
double d;
493-
if ((str.find_first_of('.') == std::string::npos) && (str.find_first_of('e') == std::string::npos) && (str.find_first_of('E') == std::string::npos)) {
494-
l = stringToLong(str, &ok);
495-
isLong = true;
496-
} else
497-
d = stringToDouble(str, &ok);
498-
if (ok) {
499-
if (isLong) {
494+
int type = checkString(str, &l, &d);
495+
496+
switch (type) {
497+
case 1:
500498
*this = l;
501499
m_type = Type::Integer;
502-
} else {
500+
break;
501+
case 2:
503502
*this = d;
504503
m_type = Type::Double;
505-
}
504+
break;
505+
default:
506+
break;
506507
}
507508
}
508509

@@ -532,9 +533,30 @@ class LIBSCRATCHCPP_EXPORT Value
532533
}
533534
}
534535
} else {
535-
if (v1.isString() || v2.isString())
536-
return stringsEqual(v1.toUtf16(), v2.toUtf16());
537-
else if (v1.isNumber() || v2.isNumber())
536+
if (v1.isString() || v2.isString()) {
537+
if (static_cast<int>(v1.m_type) < 0 || static_cast<int>(v2.m_type) < 0)
538+
return stringsEqual(v1.toUtf16(), v2.toUtf16());
539+
540+
long l1, l2;
541+
double d1, d2;
542+
int type1 = checkString(v1.toString(), &l1, &d1);
543+
int type2 = checkString(v2.toString(), &l2, &d2);
544+
545+
if (type1 == 1)
546+
d1 = l1;
547+
548+
if (type2 == 1)
549+
d2 = l2;
550+
551+
if (type1 > 0 && type2 > 0)
552+
return d1 == d2;
553+
else if (type2 > 0)
554+
return v1.toString() == doubleToString(d2);
555+
else if (type1 > 0)
556+
return doubleToString(d1) == v2.toString();
557+
else
558+
return stringsEqual(v1.toUtf16(), v2.toUtf16());
559+
} else if (v1.isNumber() || v2.isNumber())
538560
return v1.toDouble() == v2.toDouble();
539561
else if (v1.isBool() || v2.isBool())
540562
return ((v1.m_type != Type::NaN && v2.m_type != Type::NaN) && (v1.toBool() == v2.toBool()));
@@ -711,15 +733,37 @@ class LIBSCRATCHCPP_EXPORT Value
711733
}
712734

713735
static const std::string digits = "0123456789.eE+-";
714-
for (char c : s) {
736+
const std::string *stringPtr = &s;
737+
bool customStr = false;
738+
739+
if (!s.empty() && ((s[0] == ' ') || (s.back() == ' '))) {
740+
std::string *localPtr = new std::string(s);
741+
stringPtr = localPtr;
742+
customStr = true;
743+
744+
while (!localPtr->empty() && (localPtr->at(0) == ' '))
745+
localPtr->erase(0, 1);
746+
747+
while (!localPtr->empty() && (localPtr->back() == ' '))
748+
localPtr->pop_back();
749+
}
750+
751+
for (char c : *stringPtr) {
715752
if (digits.find(c) == std::string::npos) {
716753
return 0;
717754
}
718755
}
756+
719757
try {
720758
if (ok)
721759
*ok = true;
722-
return std::stod(s);
760+
761+
double ret = std::stod(*stringPtr);
762+
763+
if (customStr)
764+
delete stringPtr;
765+
766+
return ret;
723767
} catch (...) {
724768
if (ok)
725769
*ok = false;
@@ -764,6 +808,28 @@ class LIBSCRATCHCPP_EXPORT Value
764808
return 0;
765809
}
766810
}
811+
812+
static std::string doubleToString(double v)
813+
{
814+
std::stringstream stream;
815+
stream << v;
816+
std::string s = stream.str();
817+
std::size_t index;
818+
819+
for (int i = 0; i < 2; i++) {
820+
if (i == 0)
821+
index = s.find("e+");
822+
else
823+
index = s.find("e-");
824+
825+
if (index != std::string::npos) {
826+
while ((s.size() >= index + 3) && (s[index + 2] == '0'))
827+
s.erase(index + 2, 1);
828+
}
829+
}
830+
831+
return s;
832+
}
767833
};
768834

769835
} // namespace libscratchcpp

test/scratch_classes/value_test.cpp

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,16 +1787,44 @@ TEST(ValueTest, EqualityOperators)
17871787
{
17881788
Value v1 = 5.25;
17891789
Value v2 = "5.25";
1790-
Value v3 = "5.26";
1790+
Value v3 = " 5.25";
1791+
Value v4 = "5.25 ";
1792+
Value v5 = " 5.25 ";
1793+
Value v6 = " 5.25 ";
1794+
Value v7 = "5.26";
17911795

17921796
ASSERT_TRUE(v1 == v2);
17931797
ASSERT_FALSE(v1 != v2);
17941798

1795-
ASSERT_FALSE(v1 == v3);
1796-
ASSERT_TRUE(v1 != v3);
1799+
ASSERT_TRUE(v1 == v3);
1800+
ASSERT_FALSE(v1 != v3);
17971801

1798-
ASSERT_FALSE(v2 == v3);
1799-
ASSERT_TRUE(v2 != v3);
1802+
ASSERT_TRUE(v1 == v4);
1803+
ASSERT_FALSE(v1 != v4);
1804+
1805+
ASSERT_TRUE(v1 == v5);
1806+
ASSERT_FALSE(v1 != v5);
1807+
1808+
ASSERT_TRUE(v1 == v6);
1809+
ASSERT_FALSE(v1 != v6);
1810+
1811+
ASSERT_FALSE(v1 == v7);
1812+
ASSERT_TRUE(v1 != v7);
1813+
1814+
ASSERT_FALSE(v2 == v7);
1815+
ASSERT_TRUE(v2 != v7);
1816+
1817+
ASSERT_FALSE(v3 == v7);
1818+
ASSERT_TRUE(v3 != v7);
1819+
1820+
ASSERT_FALSE(v4 == v7);
1821+
ASSERT_TRUE(v4 != v7);
1822+
1823+
ASSERT_FALSE(v5 == v7);
1824+
ASSERT_TRUE(v5 != v7);
1825+
1826+
ASSERT_FALSE(v6 == v7);
1827+
ASSERT_TRUE(v6 != v7);
18001828
}
18011829

18021830
{

0 commit comments

Comments
 (0)