# HG changeset patch # User cmlenz # Date 1180958785 0 # Node ID 8b6804eac9e5c9fe62ad8966bcb1a3b71a3e8a4a # Parent df1e2f0ef627e3d8c45793a7d03c814b4ac77d96 Started docs on number formatting/parsing. diff --git a/babel/numbers.py b/babel/numbers.py --- a/babel/numbers.py +++ b/babel/numbers.py @@ -29,7 +29,7 @@ __all__ = ['format_number', 'format_decimal', 'format_currency', 'format_percent', 'format_scientific', 'parse_number', - 'parse_decimal'] + 'parse_decimal', 'NumberFormatError'] __docformat__ = 'restructuredtext en' LC_NUMERIC = default_locale('LC_NUMERIC') @@ -106,13 +106,14 @@ pattern = parse_pattern(format) return pattern.apply(number, locale) -def format_currency(number, locale=LC_NUMERIC): +def format_currency(number, currency, locale=LC_NUMERIC): """Returns formatted currency value. - >>> format_currency(1099.98, locale='en_US') + >>> format_currency(1099.98, 'USD', locale='en_US') u'1,099.98' :param number: the number to format + :param currency: the currency code :param locale: the `Locale` object or locale identifier :return: the formatted currency value :rtype: `unicode` @@ -144,6 +145,12 @@ def format_scientific(number, locale=LC_NUMERIC): raise NotImplementedError + + +class NumberFormatError(ValueError): + """Exception raised when a string cannot be parsed into a number.""" + + def parse_number(string, locale=LC_NUMERIC): """Parse localized number string into a long integer. @@ -152,32 +159,52 @@ >>> parse_number('1.099', locale='de_DE') 1099L + When the given string cannot be parsed, an exception is raised: + + >>> parse_number('1.099,98', locale='de') + Traceback (most recent call last): + ... + NumberFormatError: '1.099,98' is not a valid number + :param string: the string to parse :param locale: the `Locale` object or locale identifier :return: the parsed number :rtype: `long` - :raise `ValueError`: if the string can not be converted to a number + :raise `NumberFormatError`: if the string can not be converted to a number """ - return long(string.replace(get_group_symbol(locale), '')) + try: + return long(string.replace(get_group_symbol(locale), '')) + except ValueError: + raise NumberFormatError('%r is not a valid number' % string) def parse_decimal(string, locale=LC_NUMERIC): """Parse localized decimal string into a float. >>> parse_decimal('1,099.98', locale='en_US') 1099.98 - >>> parse_decimal('1.099,98', locale='de_DE') + >>> parse_decimal('1.099,98', locale='de') 1099.98 + When the given string cannot be parsed, an exception is raised: + + >>> parse_decimal('2,109,998', locale='de') + Traceback (most recent call last): + ... + NumberFormatError: '2,109,998' is not a valid decimal number + :param string: the string to parse :param locale: the `Locale` object or locale identifier :return: the parsed decimal number :rtype: `float` - :raise `ValueError`: if the string can not be converted to a decimal number + :raise `NumberFormatError`: if the string can not be converted to a + decimal number """ locale = Locale.parse(locale) - string = string.replace(get_group_symbol(locale), '') \ - .replace(get_decimal_symbol(locale), '.') - return float(string) + try: + return float(string.replace(get_group_symbol(locale), '') + .replace(get_decimal_symbol(locale), '.')) + except ValueError: + raise NumberFormatError('%r is not a valid decimal number' % string) PREFIX_END = r'[^0-9@#.,]' diff --git a/doc/formatting.txt b/doc/formatting.txt --- a/doc/formatting.txt +++ b/doc/formatting.txt @@ -234,10 +234,90 @@ Number Formatting ================= +Support for locale-specific formatting and parsing of numbers is provided by +the ``babel.numbers`` module:: + + >>> from babel.numbers import format_number, format_decimal, format_percent + +Examples:: + + >>> format_decimal(1.2345, locale='en_US') + u'1.234' + >>> format_decimal(1.2345, locale='sv_SE') + u'1,234' + >>> format_decimal(12345, locale='de_DE') + u'12.345' + Pattern Syntax -------------- +While Babel makes it simple to use the appropriate number format for a given +locale, you can also force it to use custom patterns. As with date/time +formatting patterns, the patterns Babel supports for number formatting are +based on the `Locale Data Markup Language specification`_ (LDML). + +Examples:: + + >>> format_decimal(-1.2345, format='#,##0.##;-#', locale='en') + u'-1.23' + >>> format_decimal(-1.2345, format='#,##0.##;(#)', locale='en') + u'(1.23)' + +The syntax for custom number format patterns is described in detail in the +the specification. The following table is just a relatively brief overview. + + +----------+-----------------------------------------------------------------+ + | Symbol | Description | + +==========+=================================================================+ + | ``0`` | Digit | + +----------+-----------------------------------------------------------------+ + | ``1-9`` | '1' through '9' indicate rounding. | + +----------+-----------------------------------------------------------------+ + | ``@`` | Significant digit | + +----------+-----------------------------------------------------------------+ + | ``#`` | Digit, zero shows as absent | + +----------+-----------------------------------------------------------------+ + | ``.`` | Decimal separator or monetary decimal separator | + +----------+-----------------------------------------------------------------+ + | ``-`` | Minus sign | + +----------+-----------------------------------------------------------------+ + | ``,`` | Grouping separator | + +----------+-----------------------------------------------------------------+ + | ``E`` | Separates mantissa and exponent in scientific notation | + +----------+-----------------------------------------------------------------+ + | ``+`` | Prefix positive exponents with localized plus sign | + +----------+-----------------------------------------------------------------+ + | ``;`` | Separates positive and negative subpatterns | + +----------+-----------------------------------------------------------------+ + | ``%`` | Multiply by 100 and show as percentage | + +----------+-----------------------------------------------------------------+ + | ``‰`` | Multiply by 1000 and show as per mille | + +----------+-----------------------------------------------------------------+ + | ``¤`` | Currency sign, replaced by currency symbol. If doubled, | + | | replaced by international currency symbol. If tripled, uses the | + | | long form of the decimal symbol. | + +----------+-----------------------------------------------------------------+ + | ``'`` | Used to quote special characters in a prefix or suffix | + +----------+-----------------------------------------------------------------+ + | ``*`` | Pad escape, precedes pad character | + +----------+-----------------------------------------------------------------+ + Parsing Numbers --------------- + +Babel can also parse numeric data in a locale-sensitive manner:: + + >>> from babel.dates import parse_decimal, parse_number + +Examples:: + + >>> parse_decimal('1,099.98', locale='en_US') + 1099.98 + >>> parse_decimal('1.099,98', locale='de') + 1099.98 + >>> parse_decimal('2,109,998', locale='de') + Traceback (most recent call last): + ... + NumberFormatError: '2,109,998' is not a valid decimal number