annotate babel/numbers.py @ 128:24a711a3c174

Add test for permille number format.
author cmlenz
date Mon, 18 Jun 2007 16:33:54 +0000
parents a72de8971819
children d6aef0675953
rev   line source
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
1 # -*- coding: utf-8 -*-
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
2 #
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
3 # Copyright (C) 2007 Edgewall Software
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
4 # All rights reserved.
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
5 #
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
6 # This software is licensed as described in the file COPYING, which
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
7 # you should have received as part of this distribution. The terms
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
8 # are also available at http://babel.edgewall.org/wiki/License.
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
9 #
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
10 # This software consists of voluntary contributions made by many
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
11 # individuals. For the exact contribution history, see the revision
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
12 # history and logs, available at http://babel.edgewall.org/log/.
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
13
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
14 """Locale dependent formatting and parsing of numeric data.
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
15
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
16 The default locale for the functions in this module is determined by the
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
17 following environment variables, in that order:
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
18
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
19 * ``LC_NUMERIC``,
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
20 * ``LC_ALL``, and
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
21 * ``LANG``
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
22 """
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
23 # TODO: percent and scientific formatting
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
24
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
25 import re
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
26
74
d9c34d2f3d1d More explicit module-level function names in `babel.core`. Added `Locale.negotiate` class method.
cmlenz
parents: 52
diff changeset
27 from babel.core import default_locale, Locale
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
28
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
29 __all__ = ['format_number', 'format_decimal', 'format_currency',
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
30 'format_percent', 'format_scientific', 'parse_number',
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
31 'parse_decimal', 'NumberFormatError']
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
32 __docformat__ = 'restructuredtext en'
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
33
74
d9c34d2f3d1d More explicit module-level function names in `babel.core`. Added `Locale.negotiate` class method.
cmlenz
parents: 52
diff changeset
34 LC_NUMERIC = default_locale('LC_NUMERIC')
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
35
127
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
36 def get_currency_symbol(currency, locale=LC_NUMERIC):
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
37 """Return the symbol used by the locale for the specified currency.
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
38
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
39 >>> get_currency_symbol('USD', 'en_US')
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
40 u'$'
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
41
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
42 :param currency: the currency code
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
43 :param locale: the `Locale` object or locale identifier
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
44 :return: the currency symbol
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
45 :rtype: `unicode`
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
46 """
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
47 return Locale.parse(locale).currency_symbols.get(currency, currency)
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
48
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
49 def get_decimal_symbol(locale=LC_NUMERIC):
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
50 """Return the symbol used by the locale to separate decimal fractions.
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
51
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
52 >>> get_decimal_symbol('en_US')
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
53 u'.'
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
54
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
55 :param locale: the `Locale` object or locale identifier
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
56 :return: the decimal symbol
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
57 :rtype: `unicode`
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
58 """
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
59 return Locale.parse(locale).number_symbols.get('decimal', u'.')
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
60
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
61 def get_group_symbol(locale=LC_NUMERIC):
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
62 """Return the symbol used by the locale to separate groups of thousands.
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
63
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
64 >>> get_group_symbol('en_US')
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
65 u','
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
66
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
67 :param locale: the `Locale` object or locale identifier
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
68 :return: the group symbol
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
69 :rtype: `unicode`
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
70 """
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
71 return Locale.parse(locale).number_symbols.get('group', u',')
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
72
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
73 def format_number(number, locale=LC_NUMERIC):
103
1ba215a5774d Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents: 74
diff changeset
74 """Return the given number formatted for a specific locale.
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
75
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
76 >>> format_number(1099, locale='en_US')
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
77 u'1,099'
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
78
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
79 :param number: the number to format
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
80 :param locale: the `Locale` object or locale identifier
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
81 :return: the formatted number
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
82 :rtype: `unicode`
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
83 """
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
84 # Do we really need this one?
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
85 return format_decimal(number, locale=locale)
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
86
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
87 def format_decimal(number, format=None, locale=LC_NUMERIC):
103
1ba215a5774d Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents: 74
diff changeset
88 """Return the given decimal number formatted for a specific locale.
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
89
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
90 >>> format_decimal(1.2345, locale='en_US')
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
91 u'1.234'
52
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
92 >>> format_decimal(1.2346, locale='en_US')
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
93 u'1.235'
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
94 >>> format_decimal(-1.2346, locale='en_US')
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
95 u'-1.235'
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
96 >>> format_decimal(1.2345, locale='sv_SE')
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
97 u'1,234'
52
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
98 >>> format_decimal(12345, locale='de')
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
99 u'12.345'
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
100
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
101 The appropriate thousands grouping and the decimal separator are used for
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
102 each locale:
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
103
127
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
104 >>> format_decimal(12345.5, locale='en_US')
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
105 u'12,345.5'
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
106
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
107 :param number: the number to format
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
108 :param format:
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
109 :param locale: the `Locale` object or locale identifier
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
110 :return: the formatted decimal number
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
111 :rtype: `unicode`
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
112 """
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
113 locale = Locale.parse(locale)
127
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
114 if not format:
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
115 format = locale.decimal_formats.get(format)
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
116 pattern = parse_pattern(format)
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
117 return pattern.apply(number, locale)
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
118
127
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
119 def format_currency(number, currency, format=None, locale=LC_NUMERIC):
103
1ba215a5774d Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents: 74
diff changeset
120 """Return formatted currency value.
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
121
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
122 >>> format_currency(1099.98, 'USD', locale='en_US')
127
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
123 u'$1,099.98'
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
124 >>> format_currency(1099.98, 'USD', locale='es_CO')
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
125 u'US$1.099,98'
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
126 >>> format_currency(1099.98, 'EUR', locale='de_DE')
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
127 u'1.099,98 \\u20ac'
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
128
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
129 The pattern can also be specified explicitly:
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
130
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
131 >>> format_currency(1099.98, 'EUR', u'\xa4\xa4 #,##0.00', locale='en_US')
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
132 u'EUR 1,099.98'
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
133
28
695884591af6 * Reduce size of locale data pickles by only storing the data provided by each locale itself, and merging inherited data at runtime.
cmlenz
parents: 24
diff changeset
134 :param number: the number to format
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
135 :param currency: the currency code
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
136 :param locale: the `Locale` object or locale identifier
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
137 :return: the formatted currency value
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
138 :rtype: `unicode`
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
139 """
127
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
140 locale = Locale.parse(locale)
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
141 if not format:
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
142 format = locale.currency_formats.get(format)
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
143 pattern = parse_pattern(format)
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
144 return pattern.apply(number, locale, currency=currency)
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
145
28
695884591af6 * Reduce size of locale data pickles by only storing the data provided by each locale itself, and merging inherited data at runtime.
cmlenz
parents: 24
diff changeset
146 def format_percent(number, format=None, locale=LC_NUMERIC):
103
1ba215a5774d Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents: 74
diff changeset
147 """Return formatted percent value for a specific locale.
24
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
148
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
149 >>> format_percent(0.34, locale='en_US')
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
150 u'34%'
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
151 >>> format_percent(25.1234, locale='en_US')
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
152 u'2,512%'
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
153 >>> format_percent(25.1234, locale='sv_SE')
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
154 u'2\\xa0512 %'
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
155
128
24a711a3c174 Add test for permille number format.
cmlenz
parents: 127
diff changeset
156 The format pattern can also be specified explicitly:
24a711a3c174 Add test for permille number format.
cmlenz
parents: 127
diff changeset
157
24a711a3c174 Add test for permille number format.
cmlenz
parents: 127
diff changeset
158 >>> format_percent(25.1234, u'#,##0\u2030', locale='en_US')
24a711a3c174 Add test for permille number format.
cmlenz
parents: 127
diff changeset
159 u'25,123\u2030'
24a711a3c174 Add test for permille number format.
cmlenz
parents: 127
diff changeset
160
24
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
161 :param number: the percent number to format
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
162 :param format:
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
163 :param locale: the `Locale` object or locale identifier
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
164 :return: the formatted percent number
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
165 :rtype: `unicode`
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
166 """
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
167 locale = Locale.parse(locale)
127
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
168 if not format:
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
169 format = locale.percent_formats.get(format)
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
170 pattern = parse_pattern(format)
28
695884591af6 * Reduce size of locale data pickles by only storing the data provided by each locale itself, and merging inherited data at runtime.
cmlenz
parents: 24
diff changeset
171 return pattern.apply(number, locale)
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
172
28
695884591af6 * Reduce size of locale data pickles by only storing the data provided by each locale itself, and merging inherited data at runtime.
cmlenz
parents: 24
diff changeset
173 def format_scientific(number, locale=LC_NUMERIC):
128
24a711a3c174 Add test for permille number format.
cmlenz
parents: 127
diff changeset
174 # TODO: implement
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
175 raise NotImplementedError
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
176
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
177
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
178 class NumberFormatError(ValueError):
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
179 """Exception raised when a string cannot be parsed into a number."""
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
180
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
181
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
182 def parse_number(string, locale=LC_NUMERIC):
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
183 """Parse localized number string into a long integer.
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
184
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
185 >>> parse_number('1,099', locale='en_US')
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
186 1099L
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
187 >>> parse_number('1.099', locale='de_DE')
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
188 1099L
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
189
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
190 When the given string cannot be parsed, an exception is raised:
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
191
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
192 >>> parse_number('1.099,98', locale='de')
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
193 Traceback (most recent call last):
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
194 ...
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
195 NumberFormatError: '1.099,98' is not a valid number
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
196
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
197 :param string: the string to parse
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
198 :param locale: the `Locale` object or locale identifier
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
199 :return: the parsed number
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
200 :rtype: `long`
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
201 :raise `NumberFormatError`: if the string can not be converted to a number
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
202 """
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
203 try:
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
204 return long(string.replace(get_group_symbol(locale), ''))
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
205 except ValueError:
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
206 raise NumberFormatError('%r is not a valid number' % string)
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
207
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
208 def parse_decimal(string, locale=LC_NUMERIC):
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
209 """Parse localized decimal string into a float.
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
210
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
211 >>> parse_decimal('1,099.98', locale='en_US')
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
212 1099.98
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
213 >>> parse_decimal('1.099,98', locale='de')
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
214 1099.98
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
215
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
216 When the given string cannot be parsed, an exception is raised:
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
217
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
218 >>> parse_decimal('2,109,998', locale='de')
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
219 Traceback (most recent call last):
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
220 ...
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
221 NumberFormatError: '2,109,998' is not a valid decimal number
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
222
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
223 :param string: the string to parse
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
224 :param locale: the `Locale` object or locale identifier
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
225 :return: the parsed decimal number
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
226 :rtype: `float`
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
227 :raise `NumberFormatError`: if the string can not be converted to a
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
228 decimal number
3
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
229 """
e9eaddab598e Import of initial code base.
cmlenz
parents:
diff changeset
230 locale = Locale.parse(locale)
34
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
231 try:
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
232 return float(string.replace(get_group_symbol(locale), '')
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
233 .replace(get_decimal_symbol(locale), '.'))
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
234 except ValueError:
8b6804eac9e5 Started docs on number formatting/parsing.
cmlenz
parents: 28
diff changeset
235 raise NumberFormatError('%r is not a valid decimal number' % string)
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
236
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
237
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
238 PREFIX_END = r'[^0-9@#.,]'
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
239 NUMBER_TOKEN = r'[0-9@#.\-,E]'
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
240
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
241 PREFIX_PATTERN = r"(?P<prefix>(?:'[^']*'|%s)*)" % PREFIX_END
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
242 NUMBER_PATTERN = r"(?P<number>%s+)" % NUMBER_TOKEN
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
243 SUFFIX_PATTERN = r"(?P<suffix>.*)"
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
244
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
245 number_re = re.compile(r"%s%s%s" % (PREFIX_PATTERN, NUMBER_PATTERN,
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
246 SUFFIX_PATTERN))
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
247
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
248 # TODO:
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
249 # Filling
52
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
250 # Rounding increment in pattern
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
251 # Scientific notation
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
252 # Significant Digits
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
253 def parse_pattern(pattern):
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
254 """Parse number format patterns"""
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
255 if isinstance(pattern, NumberPattern):
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
256 return pattern
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
257
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
258 # Do we have a negative subpattern?
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
259 if ';' in pattern:
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
260 pattern, neg_pattern = pattern.split(';', 1)
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
261 pos_prefix, number, pos_suffix = number_re.search(pattern).groups()
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
262 neg_prefix, _, neg_suffix = number_re.search(neg_pattern).groups()
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
263 else:
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
264 pos_prefix, number, pos_suffix = number_re.search(pattern).groups()
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
265 neg_prefix = '-' + pos_prefix
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
266 neg_suffix = pos_suffix
24
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
267 if '.' in number:
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
268 integer, fraction = number.rsplit('.', 1)
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
269 else:
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
270 integer = number
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
271 fraction = ''
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
272 min_frac = max_frac = 0
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
273
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
274 def parse_precision(p):
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
275 """Calculate the min and max allowed digits"""
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
276 min = max = 0
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
277 for c in p:
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
278 if c == '0':
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
279 min += 1
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
280 max += 1
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
281 elif c == '#':
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
282 max += 1
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
283 else:
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
284 break
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
285 return min, max
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
286
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
287 def parse_grouping(p):
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
288 """Parse primary and secondary digit grouping
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
289
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
290 >>> parse_grouping('##')
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
291 0, 0
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
292 >>> parse_grouping('#,###')
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
293 3, 3
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
294 >>> parse_grouping('#,####,###')
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
295 3, 4
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
296 """
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
297 width = len(p)
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
298 g1 = p.rfind(',')
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
299 if g1 == -1:
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
300 return 1000, 1000
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
301 g1 = width - g1 - 1
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
302 g2 = p[:-g1 - 1].rfind(',')
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
303 if g2 == -1:
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
304 return g1, g1
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
305 g2 = width - g1 - g2 - 2
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
306 return g1, g2
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
307
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
308 int_precision = parse_precision(integer)
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
309 frac_precision = parse_precision(fraction)
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
310 grouping = parse_grouping(integer)
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
311 int_precision = (int_precision[0], 1000) # Unlimited
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
312 return NumberPattern(pattern, (pos_prefix, neg_prefix),
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
313 (pos_suffix, neg_suffix), grouping,
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
314 int_precision, frac_precision)
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
315
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
316
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
317 class NumberPattern(object):
24
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
318
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
319 def __init__(self, pattern, prefix, suffix, grouping,
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
320 int_precision, frac_precision):
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
321 self.pattern = pattern
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
322 self.prefix = prefix
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
323 self.suffix = suffix
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
324 self.grouping = grouping
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
325 self.int_precision = int_precision
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
326 self.frac_precision = frac_precision
52
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
327 self.format = '%%.%df' % self.frac_precision[1]
24
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
328 if '%' in ''.join(self.prefix + self.suffix):
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
329 self.scale = 100.0
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
330 elif u'‰' in ''.join(self.prefix + self.suffix):
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
331 self.scale = 1000.0
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
332 else:
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
333 self.scale = 1.0
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
334
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
335 def __repr__(self):
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
336 return '<%s %r>' % (type(self).__name__, self.pattern)
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
337
127
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
338 def apply(self, value, locale, currency=None):
24
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
339 value *= self.scale
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
340 negative = int(value < 0)
52
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
341 a = self.format % value
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
342 if self.frac_precision[1] > 0:
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
343 a, b = a.split('.')
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
344 else:
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
345 b = ''
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
346 a = a.lstrip('-')
128
24a711a3c174 Add test for permille number format.
cmlenz
parents: 127
diff changeset
347 retval = u'%s%s%s%s' % (self.prefix[negative],
24a711a3c174 Add test for permille number format.
cmlenz
parents: 127
diff changeset
348 self._format_int(a, locale),
24a711a3c174 Add test for permille number format.
cmlenz
parents: 127
diff changeset
349 self._format_frac(b, locale),
24a711a3c174 Add test for permille number format.
cmlenz
parents: 127
diff changeset
350 self.suffix[negative])
127
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
351 if u'¤' in retval:
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
352 retval = retval.replace(u'¤¤', currency.upper())
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
353 retval = retval.replace(u'¤', get_currency_symbol(currency, locale))
a72de8971819 Add currency formatting.
cmlenz
parents: 103
diff changeset
354 return retval
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
355
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
356 def _format_int(self, value, locale):
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
357 min, max = self.int_precision
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
358 width = len(value)
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
359 if width < min:
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
360 value += '0' * (min - width)
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
361 gsize = self.grouping[0]
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
362 ret = ''
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
363 symbol = get_group_symbol(locale)
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
364 while len(value) > gsize:
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
365 ret = symbol + value[-gsize:] + ret
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
366 value = value[:-gsize]
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
367 gsize = self.grouping[1]
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
368 return value + ret
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
369
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
370 def _format_frac(self, value, locale):
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
371 min, max = self.frac_precision
24
6c2c9fc7d787 Implemented babel.numbers.format_percent
jonas
parents: 11
diff changeset
372 if max == 0 or (min == 0 and int(value) == 0):
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
373 return ''
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
374 width = len(value)
52
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
375 while len(value) > min and value[-1] == '0':
4df5e8994657 Added round-half-even (banker's rounding) support.
jonas
parents: 41
diff changeset
376 value = value[:-1]
11
11f64b232b04 Add basic support for number format patterns.
jonas
parents: 3
diff changeset
377 return get_decimal_symbol(locale) + value
Copyright (C) 2012-2017 Edgewall Software