numbers.py 19 KB

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