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