__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')
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`
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.
>>> 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@#.,]'
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