raise NumberFormatError(f"{string!r} is not a valid decimal number") from exc
if strict and group_symbol in string:
proper = format_decimal(parsed, locale=locale, decimal_quantization=False, numbering_system=numbering_system)
- if string != proper and string.rstrip('0') != (proper + decimal_symbol):
+ if string != proper and proper != _remove_trailing_zeros_after_decimal(string, decimal_symbol):
try:
parsed_alt = decimal.Decimal(string.replace(decimal_symbol, '')
.replace(group_symbol, '.'))
return parsed
+def _remove_trailing_zeros_after_decimal(string: str, decimal_symbol: str) -> str:
+ """
+ Remove trailing zeros from the decimal part of a numeric string.
+
+ This function takes a string representing a numeric value and a decimal symbol.
+ It removes any trailing zeros that appear after the decimal symbol in the number.
+ If the decimal part becomes empty after removing trailing zeros, the decimal symbol
+ is also removed. If the string does not contain the decimal symbol, it is returned unchanged.
+
+ :param string: The numeric string from which to remove trailing zeros.
+ :type string: str
+ :param decimal_symbol: The symbol used to denote the decimal point.
+ :type decimal_symbol: str
+ :return: The numeric string with trailing zeros removed from its decimal part.
+ :rtype: str
+
+ Example:
+ >>> _remove_trailing_zeros_after_decimal("123.4500", ".")
+ '123.45'
+ >>> _remove_trailing_zeros_after_decimal("100.000", ".")
+ '100'
+ >>> _remove_trailing_zeros_after_decimal("100", ".")
+ '100'
+ """
+ integer_part, _, decimal_part = string.partition(decimal_symbol)
+
+ if decimal_part:
+ decimal_part = decimal_part.rstrip("0")
+ if decimal_part:
+ return integer_part + decimal_symbol + decimal_part
+ return integer_part
+
+ return string
+
+
PREFIX_END = r'[^0-9@#.,]'
NUMBER_TOKEN = r'[0-9@#.,E+]'
with pytest.raises(numbers.UnsupportedNumberingSystemError):
numbers.parse_decimal('2,109,998', locale='de', numbering_system="unknown")
-
def test_parse_decimal_strict_mode(self):
# Numbers with a misplaced grouping symbol should be rejected
with pytest.raises(numbers.NumberFormatError) as info:
assert str(numbers.parse_decimal('1.001', locale='de', strict=True)) == '1001'
# Trailing zeroes should be accepted
assert str(numbers.parse_decimal('3.00', locale='en_US', strict=True)) == '3.00'
+ # Numbers with a grouping symbol and no trailing zeroes should be accepted
+ assert str(numbers.parse_decimal('3,400.6', locale='en_US', strict=True)) == '3400.6'
+ # Numbers with a grouping symbol and trailing zeroes (not all zeroes after decimal) should be accepted
+ assert str(numbers.parse_decimal('3,400.60', locale='en_US', strict=True)) == '3400.60'
+ # Numbers with a grouping symbol and trailing zeroes (all zeroes after decimal) should be accepted
+ assert str(numbers.parse_decimal('3,400.00', locale='en_US', strict=True)) == '3400.00'
+ assert str(numbers.parse_decimal('3,400.0000', locale='en_US', strict=True)) == '3400.0000'
+ # Numbers with a grouping symbol and no decimal part should be accepted
+ assert str(numbers.parse_decimal('3,800', locale='en_US', strict=True)) == '3800'
# Numbers without any grouping symbol should be accepted
assert str(numbers.parse_decimal('2000.1', locale='en_US', strict=True)) == '2000.1'
+ # Numbers without any grouping symbol and no decimal should be accepted
+ assert str(numbers.parse_decimal('2580', locale='en_US', strict=True)) == '2580'
# High precision numbers should be accepted
assert str(numbers.parse_decimal('5,000001', locale='fr', strict=True)) == '5.000001'