mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
[gnc-numeric.cpp] parse integer + fraction; e.g."10 1/4" == 10.25
This commit is contained in:
@@ -208,21 +208,24 @@ numeric_from_scientific_match(smatch &m)
|
||||
}
|
||||
|
||||
GncNumeric::GncNumeric(const std::string &str, bool autoround) {
|
||||
static const std::string numer_frag("(-?[0-9]*)");
|
||||
static const std::string denom_frag("([0-9]+)");
|
||||
static const std::string maybe_sign ("(-?)");
|
||||
static const std::string opt_signed_int("(-?[0-9]*)");
|
||||
static const std::string unsigned_int("([0-9]+)");
|
||||
static const std::string hex_frag("(0[xX][A-Fa-f0-9]+)");
|
||||
static const std::string slash("[ \\t]*/[ \\t]*");
|
||||
static const std::string whitespace("[ \\t]+");
|
||||
/* The llvm standard C++ library refused to recognize the - in the
|
||||
* numer_frag pattern with the default ECMAScript syntax so we use the
|
||||
* opt_signed_int pattern with the default ECMAScript syntax so we use the
|
||||
* awk syntax.
|
||||
*/
|
||||
static const regex numeral(numer_frag);
|
||||
static const regex numeral(opt_signed_int);
|
||||
static const regex hex(hex_frag);
|
||||
static const regex numeral_rational(numer_frag + slash + denom_frag);
|
||||
static const regex numeral_rational(opt_signed_int + slash + unsigned_int);
|
||||
static const regex integer_and_fraction(maybe_sign + unsigned_int + whitespace + unsigned_int + slash + unsigned_int);
|
||||
static const regex hex_rational(hex_frag + slash + hex_frag);
|
||||
static const regex hex_over_num(hex_frag + slash + denom_frag);
|
||||
static const regex num_over_hex(numer_frag + slash + hex_frag);
|
||||
static const regex decimal(numer_frag + "[.,]" + denom_frag);
|
||||
static const regex hex_over_num(hex_frag + slash + unsigned_int);
|
||||
static const regex num_over_hex(opt_signed_int + slash + hex_frag);
|
||||
static const regex decimal(opt_signed_int + "[.,]" + unsigned_int);
|
||||
static const regex scientific("(?:(-?[0-9]+[.,]?)|(-?[0-9]*)[.,]([0-9]+))[Ee](-?[0-9]+)");
|
||||
static const regex has_hex_prefix(".*0[xX]$");
|
||||
smatch m, x;
|
||||
@@ -256,6 +259,14 @@ GncNumeric::GncNumeric(const std::string &str, bool autoround) {
|
||||
m_den = n.denom();
|
||||
return;
|
||||
}
|
||||
if (regex_search(str, m, integer_and_fraction))
|
||||
{
|
||||
GncNumeric n(stoll(m[3].str()), stoll(m[4].str()));
|
||||
n += stoll(m[2].str());
|
||||
m_num = m[1].str().empty() ? n.num() : -n.num();
|
||||
m_den = n.denom();
|
||||
return;
|
||||
}
|
||||
if (regex_search(str, m, numeral_rational))
|
||||
{
|
||||
GncNumeric n(stoll(m[1].str()), stoll(m[2].str()));
|
||||
@@ -1303,19 +1314,19 @@ gnc_num_dbg_to_string(gnc_numeric n)
|
||||
return p;
|
||||
}
|
||||
|
||||
gboolean
|
||||
string_to_gnc_numeric(const gchar* str, gnc_numeric *n)
|
||||
gnc_numeric
|
||||
gnc_numeric_from_string (const gchar* str)
|
||||
{
|
||||
if (!str)
|
||||
return gnc_numeric_error (GNC_ERROR_ARG);
|
||||
try
|
||||
{
|
||||
GncNumeric an(str);
|
||||
*n = static_cast<gnc_numeric>(an);
|
||||
return TRUE;
|
||||
return GncNumeric (str);
|
||||
}
|
||||
catch (const std::exception& err)
|
||||
{
|
||||
PWARN("%s", err.what());
|
||||
return FALSE;
|
||||
return gnc_numeric_error (GNC_ERROR_ARG);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -296,10 +296,9 @@ gnc_numeric double_to_gnc_numeric(double n, gint64 denom,
|
||||
gint how);
|
||||
|
||||
/** Read a gnc_numeric from str, skipping any leading whitespace.
|
||||
* Return TRUE on success and store the resulting value in "n".
|
||||
* Return NULL on error. */
|
||||
gboolean string_to_gnc_numeric(const gchar* str, gnc_numeric *n);
|
||||
|
||||
* Returns the resulting gnc_numeric.
|
||||
* Return GNC_ERROR_ARG on error. */
|
||||
gnc_numeric gnc_numeric_from_string (const gchar* str);
|
||||
/** Create a gnc_numeric object that signals the error condition
|
||||
* noted by error_code, rather than a number.
|
||||
*/
|
||||
|
||||
@@ -180,6 +180,28 @@ TEST(gncnumeric_constructors, test_string_constructor)
|
||||
GncNumeric neg_embedded("The number is -123456/456");
|
||||
EXPECT_EQ(-123456, neg_embedded.num());
|
||||
EXPECT_EQ(456, neg_embedded.denom());
|
||||
ASSERT_NO_THROW(GncNumeric integer_fraction("The number is 1234 567/890"));
|
||||
GncNumeric integer_fraction("The number is 1234 567/890");
|
||||
EXPECT_EQ(1098827, integer_fraction.num());
|
||||
EXPECT_EQ(890, integer_fraction.denom());
|
||||
ASSERT_NO_THROW(GncNumeric neg_integer_fraction("The number is -1234 567/890"));
|
||||
GncNumeric neg_integer_fraction("The number is -1234 567/890");
|
||||
EXPECT_EQ(-1098827, neg_integer_fraction.num());
|
||||
EXPECT_EQ(890, neg_integer_fraction.denom());
|
||||
GncNumeric integer_large_fraction("The number is 1234 4567/890");
|
||||
EXPECT_EQ(1102827, integer_large_fraction.num());
|
||||
EXPECT_EQ(890, integer_large_fraction.denom());
|
||||
GncNumeric neg_integer_large_fraction("The number is -1234 4567/890");
|
||||
EXPECT_EQ(-1102827, neg_integer_large_fraction.num());
|
||||
EXPECT_EQ(890, neg_integer_large_fraction.denom());
|
||||
ASSERT_NO_THROW(GncNumeric zero_integer_fraction("The number is 0 567/890"));
|
||||
GncNumeric zero_integer_fraction("The number is 0 567/890");
|
||||
EXPECT_EQ(567, zero_integer_fraction.num());
|
||||
EXPECT_EQ(890, zero_integer_fraction.denom());
|
||||
ASSERT_NO_THROW(GncNumeric neg_zero_integer_fraction("The number is -0 567/890"));
|
||||
GncNumeric neg_zero_integer_fraction("The number is -0 567/890");
|
||||
EXPECT_EQ(-567, neg_zero_integer_fraction.num());
|
||||
EXPECT_EQ(890, neg_zero_integer_fraction.denom());
|
||||
EXPECT_THROW(GncNumeric throw_zero_denom("123/0"), std::invalid_argument);
|
||||
EXPECT_THROW(GncNumeric overflow("12345678987654321.123456"),
|
||||
std::overflow_error);
|
||||
|
||||
Reference in New Issue
Block a user