annotate babel/numbers.py @ 26:6041782ea677 trunk

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