Mercurial > babel > old > mirror
annotate babel/numbers.py @ 214:5f90da6265a9
Switched to using our own round() implementation.
This way we can be sure the correct rounding algorithm (banker's rounding)
is used on all platforms.
author | jonas |
---|---|
date | Tue, 10 Jul 2007 21:20:07 +0000 |
parents | b13f3bf4c208 |
children | ce3ad60145db |
rev | line source |
---|---|
3 | 1 # -*- coding: utf-8 -*- |
2 # | |
3 # Copyright (C) 2007 Edgewall Software | |
4 # All rights reserved. | |
5 # | |
6 # This software is licensed as described in the file COPYING, which | |
7 # you should have received as part of this distribution. The terms | |
8 # are also available at http://babel.edgewall.org/wiki/License. | |
9 # | |
10 # This software consists of voluntary contributions made by many | |
11 # individuals. For the exact contribution history, see the revision | |
12 # history and logs, available at http://babel.edgewall.org/log/. | |
13 | |
14 """Locale dependent formatting and parsing of numeric data. | |
15 | |
16 The default locale for the functions in this module is determined by the | |
17 following environment variables, in that order: | |
18 | |
19 * ``LC_NUMERIC``, | |
20 * ``LC_ALL``, and | |
21 * ``LANG`` | |
22 """ | |
23 # TODO: percent and scientific formatting | |
24 | |
25 import re | |
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 | 28 |
29 __all__ = ['format_number', 'format_decimal', 'format_currency', | |
30 'format_percent', 'format_scientific', 'parse_number', | |
34 | 31 'parse_decimal', 'NumberFormatError'] |
3 | 32 __docformat__ = 'restructuredtext en' |
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 | 35 |
127 | 36 def get_currency_symbol(currency, locale=LC_NUMERIC): |
37 """Return the symbol used by the locale for the specified currency. | |
38 | |
39 >>> get_currency_symbol('USD', 'en_US') | |
40 u'$' | |
41 | |
42 :param currency: the currency code | |
43 :param locale: the `Locale` object or locale identifier | |
44 :return: the currency symbol | |
45 :rtype: `unicode` | |
46 """ | |
47 return Locale.parse(locale).currency_symbols.get(currency, currency) | |
48 | |
3 | 49 def get_decimal_symbol(locale=LC_NUMERIC): |
50 """Return the symbol used by the locale to separate decimal fractions. | |
51 | |
52 >>> get_decimal_symbol('en_US') | |
53 u'.' | |
54 | |
55 :param locale: the `Locale` object or locale identifier | |
56 :return: the decimal symbol | |
57 :rtype: `unicode` | |
58 """ | |
59 return Locale.parse(locale).number_symbols.get('decimal', u'.') | |
60 | |
61 def get_group_symbol(locale=LC_NUMERIC): | |
62 """Return the symbol used by the locale to separate groups of thousands. | |
63 | |
64 >>> get_group_symbol('en_US') | |
65 u',' | |
66 | |
67 :param locale: the `Locale` object or locale identifier | |
68 :return: the group symbol | |
69 :rtype: `unicode` | |
70 """ | |
11 | 71 return Locale.parse(locale).number_symbols.get('group', u',') |
3 | 72 |
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 | 75 |
76 >>> format_number(1099, locale='en_US') | |
77 u'1,099' | |
78 | |
79 :param number: the number to format | |
80 :param locale: the `Locale` object or locale identifier | |
81 :return: the formatted number | |
82 :rtype: `unicode` | |
83 """ | |
11 | 84 # Do we really need this one? |
85 return format_decimal(number, locale=locale) | |
3 | 86 |
11 | 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 | 89 |
11 | 90 >>> format_decimal(1.2345, locale='en_US') |
91 u'1.234' | |
52 | 92 >>> format_decimal(1.2346, locale='en_US') |
93 u'1.235' | |
94 >>> format_decimal(-1.2346, locale='en_US') | |
95 u'-1.235' | |
11 | 96 >>> format_decimal(1.2345, locale='sv_SE') |
97 u'1,234' | |
52 | 98 >>> format_decimal(12345, locale='de') |
11 | 99 u'12.345' |
100 | |
3 | 101 The appropriate thousands grouping and the decimal separator are used for |
102 each locale: | |
103 | |
127 | 104 >>> format_decimal(12345.5, locale='en_US') |
105 u'12,345.5' | |
11 | 106 |
3 | 107 :param number: the number to format |
11 | 108 :param format: |
3 | 109 :param locale: the `Locale` object or locale identifier |
110 :return: the formatted decimal number | |
111 :rtype: `unicode` | |
112 """ | |
113 locale = Locale.parse(locale) | |
127 | 114 if not format: |
115 format = locale.decimal_formats.get(format) | |
116 pattern = parse_pattern(format) | |
11 | 117 return pattern.apply(number, locale) |
3 | 118 |
127 | 119 def format_currency(number, currency, format=None, locale=LC_NUMERIC): |
135 | 120 u"""Return formatted currency value. |
3 | 121 |
34 | 122 >>> format_currency(1099.98, 'USD', locale='en_US') |
127 | 123 u'$1,099.98' |
124 >>> format_currency(1099.98, 'USD', locale='es_CO') | |
125 u'US$1.099,98' | |
126 >>> format_currency(1099.98, 'EUR', locale='de_DE') | |
127 u'1.099,98 \\u20ac' | |
128 | |
129 The pattern can also be specified explicitly: | |
130 | |
131 >>> format_currency(1099.98, 'EUR', u'\xa4\xa4 #,##0.00', locale='en_US') | |
132 u'EUR 1,099.98' | |
3 | 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 | 135 :param currency: the currency code |
3 | 136 :param locale: the `Locale` object or locale identifier |
137 :return: the formatted currency value | |
138 :rtype: `unicode` | |
139 """ | |
127 | 140 locale = Locale.parse(locale) |
141 if not format: | |
142 format = locale.currency_formats.get(format) | |
143 pattern = parse_pattern(format) | |
144 return pattern.apply(number, locale, currency=currency) | |
3 | 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 | 148 |
149 >>> format_percent(0.34, locale='en_US') | |
150 u'34%' | |
151 >>> format_percent(25.1234, locale='en_US') | |
152 u'2,512%' | |
153 >>> format_percent(25.1234, locale='sv_SE') | |
154 u'2\\xa0512 %' | |
155 | |
128 | 156 The format pattern can also be specified explicitly: |
157 | |
158 >>> format_percent(25.1234, u'#,##0\u2030', locale='en_US') | |
159 u'25,123\u2030' | |
160 | |
24 | 161 :param number: the percent number to format |
162 :param format: | |
163 :param locale: the `Locale` object or locale identifier | |
164 :return: the formatted percent number | |
165 :rtype: `unicode` | |
166 """ | |
167 locale = Locale.parse(locale) | |
127 | 168 if not format: |
169 format = locale.percent_formats.get(format) | |
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 | 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 | 174 # TODO: implement |
3 | 175 raise NotImplementedError |
176 | |
34 | 177 |
178 class NumberFormatError(ValueError): | |
179 """Exception raised when a string cannot be parsed into a number.""" | |
180 | |
181 | |
3 | 182 def parse_number(string, locale=LC_NUMERIC): |
183 """Parse localized number string into a long integer. | |
184 | |
185 >>> parse_number('1,099', locale='en_US') | |
186 1099L | |
187 >>> parse_number('1.099', locale='de_DE') | |
188 1099L | |
189 | |
34 | 190 When the given string cannot be parsed, an exception is raised: |
191 | |
192 >>> parse_number('1.099,98', locale='de') | |
193 Traceback (most recent call last): | |
194 ... | |
195 NumberFormatError: '1.099,98' is not a valid number | |
196 | |
3 | 197 :param string: the string to parse |
198 :param locale: the `Locale` object or locale identifier | |
199 :return: the parsed number | |
200 :rtype: `long` | |
34 | 201 :raise `NumberFormatError`: if the string can not be converted to a number |
3 | 202 """ |
34 | 203 try: |
204 return long(string.replace(get_group_symbol(locale), '')) | |
205 except ValueError: | |
206 raise NumberFormatError('%r is not a valid number' % string) | |
3 | 207 |
208 def parse_decimal(string, locale=LC_NUMERIC): | |
209 """Parse localized decimal string into a float. | |
210 | |
211 >>> parse_decimal('1,099.98', locale='en_US') | |
212 1099.98 | |
34 | 213 >>> parse_decimal('1.099,98', locale='de') |
3 | 214 1099.98 |
215 | |
34 | 216 When the given string cannot be parsed, an exception is raised: |
217 | |
218 >>> parse_decimal('2,109,998', locale='de') | |
219 Traceback (most recent call last): | |
220 ... | |
221 NumberFormatError: '2,109,998' is not a valid decimal number | |
222 | |
3 | 223 :param string: the string to parse |
224 :param locale: the `Locale` object or locale identifier | |
225 :return: the parsed decimal number | |
226 :rtype: `float` | |
34 | 227 :raise `NumberFormatError`: if the string can not be converted to a |
228 decimal number | |
3 | 229 """ |
230 locale = Locale.parse(locale) | |
34 | 231 try: |
232 return float(string.replace(get_group_symbol(locale), '') | |
233 .replace(get_decimal_symbol(locale), '.')) | |
234 except ValueError: | |
235 raise NumberFormatError('%r is not a valid decimal number' % string) | |
11 | 236 |
237 | |
238 PREFIX_END = r'[^0-9@#.,]' | |
239 NUMBER_TOKEN = r'[0-9@#.\-,E]' | |
240 | |
241 PREFIX_PATTERN = r"(?P<prefix>(?:'[^']*'|%s)*)" % PREFIX_END | |
242 NUMBER_PATTERN = r"(?P<number>%s+)" % NUMBER_TOKEN | |
243 SUFFIX_PATTERN = r"(?P<suffix>.*)" | |
244 | |
129 | 245 number_re = re.compile(r"%s%s%s" % (PREFIX_PATTERN, NUMBER_PATTERN, |
11 | 246 SUFFIX_PATTERN)) |
247 | |
214 | 248 def bankersround(value, ndigits=0): |
249 """Round a number to a given precision. | |
250 | |
251 Works like round() except that the round-half-even (banker's rounding) | |
252 algorithm is used instead of round-half-up. | |
253 | |
254 >>> bankersround(5.5, 0) | |
255 6.0 | |
256 >>> bankersround(6.5, 0) | |
257 6.0 | |
258 >>> bankersround(-6.5, 0) | |
259 -6.0 | |
260 >>> bankersround(1234, -2) | |
261 1200.0 | |
262 """ | |
263 sign = int(value < 0) and -1 or 1 | |
264 value = abs(value) | |
265 a, b = str(float(value)).split('.', 1) | |
266 digits = str(float(value)).replace('.', '') | |
267 add = 0 | |
268 i = len(a) + ndigits | |
269 if i < 0 or i >= len(digits): | |
270 pass | |
271 elif digits[i] > '5': | |
272 add = 1 | |
273 elif digits[i] == '5' and digits[i-1] in '13579': | |
274 add = 1 | |
275 scale = 10.**ndigits | |
276 return int(value * scale + add) / scale * sign | |
277 | |
11 | 278 # TODO: |
279 # Filling | |
52 | 280 # Rounding increment in pattern |
11 | 281 # Scientific notation |
282 def parse_pattern(pattern): | |
283 """Parse number format patterns""" | |
284 if isinstance(pattern, NumberPattern): | |
285 return pattern | |
286 | |
287 # Do we have a negative subpattern? | |
288 if ';' in pattern: | |
289 pattern, neg_pattern = pattern.split(';', 1) | |
290 pos_prefix, number, pos_suffix = number_re.search(pattern).groups() | |
291 neg_prefix, _, neg_suffix = number_re.search(neg_pattern).groups() | |
292 else: | |
293 pos_prefix, number, pos_suffix = number_re.search(pattern).groups() | |
294 neg_prefix = '-' + pos_prefix | |
295 neg_suffix = pos_suffix | |
213
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
296 if '@' in number: |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
297 if '.' in number and '0' in number: |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
298 raise ValueError('Significant digit patterns can not contain ' |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
299 '"@" or "0"') |
24 | 300 if '.' in number: |
301 integer, fraction = number.rsplit('.', 1) | |
302 else: | |
303 integer = number | |
304 fraction = '' | |
11 | 305 min_frac = max_frac = 0 |
306 | |
307 def parse_precision(p): | |
308 """Calculate the min and max allowed digits""" | |
309 min = max = 0 | |
310 for c in p: | |
213
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
311 if c in '@0': |
11 | 312 min += 1 |
313 max += 1 | |
314 elif c == '#': | |
315 max += 1 | |
213
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
316 elif c == ',': |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
317 continue |
11 | 318 else: |
319 break | |
320 return min, max | |
321 | |
322 def parse_grouping(p): | |
323 """Parse primary and secondary digit grouping | |
324 | |
325 >>> parse_grouping('##') | |
326 0, 0 | |
327 >>> parse_grouping('#,###') | |
328 3, 3 | |
329 >>> parse_grouping('#,####,###') | |
330 3, 4 | |
331 """ | |
332 width = len(p) | |
333 g1 = p.rfind(',') | |
334 if g1 == -1: | |
335 return 1000, 1000 | |
336 g1 = width - g1 - 1 | |
337 g2 = p[:-g1 - 1].rfind(',') | |
338 if g2 == -1: | |
339 return g1, g1 | |
340 g2 = width - g1 - g2 - 2 | |
341 return g1, g2 | |
342 | |
343 int_precision = parse_precision(integer) | |
344 frac_precision = parse_precision(fraction) | |
345 grouping = parse_grouping(integer) | |
213
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
346 if not '@' in pattern: |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
347 int_precision = (int_precision[0], 1000) # Unlimited |
11 | 348 return NumberPattern(pattern, (pos_prefix, neg_prefix), |
349 (pos_suffix, neg_suffix), grouping, | |
350 int_precision, frac_precision) | |
351 | |
352 | |
353 class NumberPattern(object): | |
24 | 354 |
11 | 355 def __init__(self, pattern, prefix, suffix, grouping, |
356 int_precision, frac_precision): | |
357 self.pattern = pattern | |
358 self.prefix = prefix | |
359 self.suffix = suffix | |
360 self.grouping = grouping | |
361 self.int_precision = int_precision | |
362 self.frac_precision = frac_precision | |
24 | 363 if '%' in ''.join(self.prefix + self.suffix): |
364 self.scale = 100.0 | |
365 elif u'‰' in ''.join(self.prefix + self.suffix): | |
366 self.scale = 1000.0 | |
367 else: | |
368 self.scale = 1.0 | |
11 | 369 |
370 def __repr__(self): | |
371 return '<%s %r>' % (type(self).__name__, self.pattern) | |
372 | |
127 | 373 def apply(self, value, locale, currency=None): |
24 | 374 value *= self.scale |
11 | 375 negative = int(value < 0) |
213
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
376 if '@' in self.pattern: # Is it a siginificant digits pattern? |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
377 text = self._format_sigdig(abs(value), |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
378 self.int_precision[0], |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
379 self.int_precision[1]) |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
380 if '.' in text: |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
381 a, b = text.split('.') |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
382 a = self._format_int(a, 0, 1000, locale) |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
383 if b: |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
384 b = get_decimal_symbol(locale) + b |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
385 else: |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
386 a, b = self._format_int(text, 0, 1000, locale), '' |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
387 else: # A normal number pattern |
214 | 388 a, b = str(bankersround(abs(value), |
389 self.frac_precision[1])).split('.', 1) | |
213
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
390 a = self._format_int(a, self.int_precision[0], |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
391 self.int_precision[1], locale) |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
392 b = self._format_frac(b, locale) |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
393 retval = u'%s%s%s%s' % (self.prefix[negative], a, b, |
128 | 394 self.suffix[negative]) |
127 | 395 if u'¤' in retval: |
396 retval = retval.replace(u'¤¤', currency.upper()) | |
397 retval = retval.replace(u'¤', get_currency_symbol(currency, locale)) | |
398 return retval | |
11 | 399 |
213
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
400 def _format_sigdig(self, value, min, max): |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
401 """Convert value to a string. |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
402 |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
403 The resulting string will contain between (min, max) number of |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
404 significant digits. |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
405 """ |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
406 a, b = str(float(value)).split('.', 1) |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
407 ndecimals = len(a) |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
408 if a == '0': |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
409 ndecimals = 0 |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
410 while b.startswith('0'): |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
411 b = b[1:] |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
412 ndecimals -= 1 |
214 | 413 text = str(bankersround(value, max - ndecimals)) |
213
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
414 if text == '0.0': |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
415 text = a = '0' |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
416 b = '' |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
417 digits = 1 |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
418 else: |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
419 a, b = text.split('.', 1) |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
420 digits = len(text.replace('.', '').lstrip('0')) |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
421 # Figure out if we need to add any trailing '0':s |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
422 if len(a) >= max and a != '0': |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
423 return a |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
424 if digits < min: |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
425 b += ('0' * (min - digits)) |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
426 if b: |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
427 return '%s.%s' % (a, b) |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
428 return a |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
429 |
b13f3bf4c208
Added support for siginificant digits in number patterns.
jonas
parents:
139
diff
changeset
|
430 def _format_int(self, value, min, max, locale): |
11 | 431 width = len(value) |
432 if width < min: | |
433 value += '0' * (min - width) | |
434 gsize = self.grouping[0] | |
435 ret = '' | |
436 symbol = get_group_symbol(locale) | |
437 while len(value) > gsize: | |
438 ret = symbol + value[-gsize:] + ret | |
439 value = value[:-gsize] | |
440 gsize = self.grouping[1] | |
441 return value + ret | |
442 | |
443 def _format_frac(self, value, locale): | |
444 min, max = self.frac_precision | |
24 | 445 if max == 0 or (min == 0 and int(value) == 0): |
11 | 446 return '' |
447 width = len(value) | |
52 | 448 while len(value) > min and value[-1] == '0': |
449 value = value[:-1] | |
11 | 450 return get_decimal_symbol(locale) + value |