/** Convert str into a GncRational using the user-specified (import) currency format. * @param str The string to be parsed * @param currency_format The currency format to use. * @return a GncNumeric * @exception May throw std::invalid argument if string can't be parsed properly */ GncNumeric parse_amount (const std::string &str, int currency_format) { /* If a cell is empty or just spaces return invalid amount */ if(!boost::regex_search(str, boost::regex("[0-9]"))) throw std::invalid_argument (_("Value doesn't appear to contain a valid number.")); auto expr = boost::make_u32regex("[[:Sc:]]"); std::string str_no_symbols = boost::u32regex_replace(str, expr, ""); /* Convert based on user chosen currency format */ gnc_numeric val; char *endptr; switch (currency_format) { case 0: /* Currency locale */ if (!(xaccParseAmount (str_no_symbols.c_str(), TRUE, &val, &endptr))) throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format.")); break; case 1: /* Currency decimal period */ if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', '.', ',', "\003\003", "$+", &val, &endptr))) throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format.")); break; case 2: /* Currency decimal comma */ if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', ',', '.', "\003\003", "$+", &val, &endptr))) throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format.")); break; } return GncNumeric(val); }
/** Convert str into a GncRational using the user-specified (import) currency format. * @param str The string to be parsed * @param currency_format The currency format to use. * @return a GncNumeric * @exception May throw std::invalid argument if string can't be parsed properly */ GncNumeric parse_amount (const std::string &str, int currency_format) { /* An empty field is treated as zero */ if (str.empty()) return GncNumeric{}; /* Strings otherwise containing not digits will be considered invalid */ if(!boost::regex_search(str, boost::regex("[0-9]"))) throw std::invalid_argument (_("Value doesn't appear to contain a valid number.")); auto expr = boost::make_u32regex("[[:Sc:]]"); std::string str_no_symbols = boost::u32regex_replace(str, expr, ""); /* Convert based on user chosen currency format */ gnc_numeric val = gnc_numeric_zero(); char *endptr; switch (currency_format) { case 0: /* Currency locale */ if (!(xaccParseAmountPosSign (str_no_symbols.c_str(), TRUE, &val, &endptr, TRUE))) throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format.")); break; case 1: /* Currency decimal period */ if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', '.', ',', "\003\003", "$+", &val, &endptr))) throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format.")); break; case 2: /* Currency decimal comma */ if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', ',', '.', "\003\003", "$+", &val, &endptr))) throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format.")); break; } return GncNumeric(val); }
/** Sets the value of the property by parsing str. Note: this should * only be called once on an instance of TransProperty, as calling it * more than once can cause memory leaks. * @param prop The property being set * @param str The string to be parsed * @return TRUE on success, FALSE on failure */ static gboolean trans_property_set (TransProperty* prop, char* str) { char *endptr, *possible_currency_symbol, *str_dupe; gnc_numeric val; int reti; regex_t regex; switch (prop->type) { case GNC_CSV_DATE: prop->value = g_new(time64, 1); *((time64*)(prop->value)) = parse_date(str, prop->list->date_format); return *((time64*)(prop->value)) != -1; case GNC_CSV_DESCRIPTION: case GNC_CSV_NOTES: case GNC_CSV_NUM: prop->value = g_strdup (str); return TRUE; case GNC_CSV_BALANCE: case GNC_CSV_DEPOSIT: case GNC_CSV_WITHDRAWAL: str_dupe = g_strdup (str); /* First, we make a copy so we can't mess up real data. */ /* If a cell is empty or just spaces make its value = "0" */ reti = regcomp(®ex, "[0-9]", 0); reti = regexec(®ex, str_dupe, 0, NULL, 0); if (reti == REG_NOMATCH) { g_free (str_dupe); str_dupe = g_strdup ("0"); } /* Go through str_dupe looking for currency symbols. */ for (possible_currency_symbol = str_dupe; *possible_currency_symbol; possible_currency_symbol = g_utf8_next_char (possible_currency_symbol)) { if (g_unichar_type (g_utf8_get_char (possible_currency_symbol)) == G_UNICODE_CURRENCY_SYMBOL) { /* If we find a currency symbol, save the position just ahead * of the currency symbol (next_symbol), and find the null * terminator of the string (last_symbol). */ char *next_symbol = g_utf8_next_char (possible_currency_symbol), *last_symbol = next_symbol; while (*last_symbol) last_symbol = g_utf8_next_char (last_symbol); /* Move all of the string (including the null byte, which is * why we have +1 in the size parameter) following the * currency symbol back one character, thereby overwriting the * currency symbol. */ memmove (possible_currency_symbol, next_symbol, last_symbol - next_symbol + 1); break; } } /* Currency format */ switch (prop->list->currency_format) { case 0: /* Currancy locale */ if (!(xaccParseAmount (str_dupe, TRUE, &val, &endptr))) { g_free (str_dupe); return FALSE; } break; case 1: /* Currancy decimal period */ if (!(xaccParseAmountExtended (str_dupe, TRUE, '-', '.', ',', "\003\003", "$+", &val, &endptr))) { g_free (str_dupe); return FALSE; } break; case 2: /* Currancy decimal comma */ if (!(xaccParseAmountExtended (str_dupe, TRUE, '-', ',', '.', "\003\003", "$+", &val, &endptr))) { g_free (str_dupe); return FALSE; } break; } prop->value = g_new (gnc_numeric, 1); *((gnc_numeric*)(prop->value)) = val; g_free (str_dupe); return TRUE; } return FALSE; /* We should never actually get here. */ }