annotate babel/numbers.py @ 101:1312ad6b624d

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