123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- <?php
- /**
- * sfNumberFormat class file.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD License.
- *
- * Copyright(c) 2004 by Qiang Xue. All rights reserved.
- *
- * To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
- * The latest version of PRADO can be obtained from:
- * {@link http://prado.sourceforge.net/}
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id: sfNumberFormat.class.php 11958 2008-10-05 16:51:39Z fabien $
- * @package symfony
- * @subpackage i18n
- */
- /**
- * sfNumberFormat class.
- *
- * sfNumberFormat formats decimal numbers in any locale. The decimal
- * number is formatted according to a particular pattern. These
- * patterns can arise from the sfNumberFormatInfo object which is
- * culturally sensitive. The sfNumberFormat class can be instantiated in
- * many ways. E.g.
- *
- * <code>
- * //create a invariant number formatter.
- * $formatter = new sfNumberFormat();
- *
- * //create a number format for the french language locale.
- * $fr = new sfNumberFormat('fr');
- *
- * //create a number format base on a sfNumberFormatInfo instance $numberInfo.
- * $format = new sfNumberFormat($numberInfo);
- * </code>
- *
- * A normal decimal number can also be displayed as a currency
- * or as a percentage. For example
- * <code>
- * $format->format(1234.5); //Decimal number "1234.5"
- * $format->format(1234.5,'c'); //Default currency "$1234.50"
- * $format->format(0.25, 'p') //Percent "25%"
- * </code>
- *
- * Currency is formated using the localized currency pattern. For example
- * to format the number as Japanese Yen:
- * <code>
- * $ja = new sfNumberFormat('ja_JP');
- *
- * //Japanese currency pattern, and using Japanese Yen symbol
- * $ja->format(123.14,'c','JPY'); //ï¿?123 (Yen 123)
- * </code>
- * For each culture, the symbol for each currency may be different.
- *
- * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version v1.0, last update on Fri Dec 10 18:10:20 EST 2004
- * @package symfony
- * @subpackage i18n
- */
- class sfNumberFormat
- {
- /**
- * The DateTimeFormatInfo, containing culture specific patterns and names.
- * @var DateTimeFormatInfo
- */
- protected $formatInfo;
- /**
- * Creates a new number format instance. The constructor can be instantiated
- * with a string that represent a culture/locale. Similarly, passing
- * a sfCultureInfo or sfNumberFormatInfo instance will instantiated a instance
- * for that particular culture.
- *
- * @param mixed $formatInfo either null, a sfCultureInfo, a sfNumberFormatInfo, or string
- * @return sfNumberFormat
- */
- function __construct($formatInfo = null)
- {
- if (is_null($formatInfo))
- {
- $this->formatInfo = sfNumberFormatInfo::getInvariantInfo();
- }
- else if ($formatInfo instanceof sfCultureInfo)
- {
- $this->formatInfo = $formatInfo->sfNumberFormat;
- }
- else if ($formatInfo instanceof sfNumberFormatInfo)
- {
- $this->formatInfo = $formatInfo;
- }
- else
- {
- $this->formatInfo = sfNumberFormatInfo::getInstance($formatInfo);
- }
- }
- /**
- * Formats the number for a certain pattern. The valid patterns are
- * 'c', 'd', 'e', 'p' or a custom pattern, such as "#.000" for
- * 3 decimal places.
- *
- * @param mixed $number the number to format.
- * @param string $pattern the format pattern, either, 'c', 'd', 'e', 'p'
- * or a custom pattern. E.g. "#.000" will format the number to
- * 3 decimal places.
- * @param string $currency 3-letter ISO 4217 code. For example, the code
- * "USD" represents the US Dollar and "EUR" represents the Euro currency.
- * @param string $charset The charset
- * @return string formatted number string
- */
- function format($number, $pattern = 'd', $currency = 'USD', $charset = 'UTF-8')
- {
- $this->setPattern($pattern);
- if (strtolower($pattern) == 'p')
- {
- $number = $number * 100;
- }
- $string = (string) $number;
- $decimal = $this->formatDecimal($string);
- $integer = $this->formatInteger(abs($number));
- $result = (strlen($decimal) > 0) ? $integer.$decimal : $integer;
- // get the suffix
- if ($number >= 0)
- {
- $suffix = $this->formatInfo->PositivePattern;
- }
- else if ($number < 0)
- {
- $suffix = $this->formatInfo->NegativePattern;
- }
- else
- {
- $suffix = array('', '');
- }
- // append and prepend suffix
- $result = $suffix[0].$result.$suffix[1];
- // replace currency sign
- $symbol = @$this->formatInfo->getCurrencySymbol($currency);
- if (is_null($symbol))
- {
- $symbol = $currency;
- }
- $result = str_replace('¤', $symbol, $result);
- return sfToolkit::I18N_toEncoding($result, $charset);
- }
- /**
- * Formats the integer, perform groupings and string padding.
- *
- * @param string $string the decimal number in string form.
- * @return string formatted integer string with grouping
- */
- protected function formatInteger($string)
- {
- $string = (string) $string;
- $decimalDigits = $this->formatInfo->DecimalDigits;
- // if not decimal digits, assume 0 decimal points.
- if (is_int($decimalDigits) && $decimalDigits > 0)
- {
- $string = (string) intval(round(floatval($string), $decimalDigits));
- }
- $dp = strpos($string, '.');
- if (is_int($dp))
- {
- $string = substr($string, 0, $dp);
- }
- $integer = '';
- $digitSize = $this->formatInfo->getDigitSize();
- $string = str_pad($string, $digitSize, '0', STR_PAD_LEFT);
- $len = strlen($string);
- $groupSeparator = $this->formatInfo->GroupSeparator;
- $groupSize = $this->formatInfo->GroupSizes;
- $firstGroup = true;
- $multiGroup = is_int($groupSize[1]);
- $count = 0;
- if (is_int($groupSize[0]))
- {
- // now for the integer groupings
- for ($i = 0; $i < $len; $i++)
- {
- $char = $string{$len - $i - 1};
- if ($multiGroup && $count == 0)
- {
- if ($i != 0 && $i % $groupSize[0] == 0)
- {
- $integer = $groupSeparator.$integer;
- $count++;
- }
- }
- else if ($multiGroup && $count >= 1)
- {
- if ($i != 0 && ($i - $groupSize[0]) % $groupSize[1] == 0)
- {
- $integer = $groupSeparator.$integer;
- $count++;
- }
- }
- else
- {
- if ($i != 0 && $i % $groupSize[0] == 0)
- {
- $integer = $groupSeparator.$integer;
- $count++;
- }
- }
- $integer = $char.$integer;
- }
- }
- else
- {
- $integer = $string;
- }
- return $integer;
- }
- /**
- * Formats the decimal places.
- *
- * @param string $decimal the decimal number in string form.
- * @return string formatted decimal places.
- */
- protected function formatDecimal($string)
- {
- $dp = strpos($string, '.');
- $decimal = '';
- $decimalDigits = $this->formatInfo->DecimalDigits;
- $decimalSeparator = $this->formatInfo->DecimalSeparator;
- if (is_int($dp))
- {
- if ($decimalDigits == -1)
- {
- $decimal = substr($string, $dp + 1);
- }
- else if (is_int($decimalDigits))
- {
- $string = $float = round((float) $string, $decimalDigits);
- if (strpos((string) $float, '.') === false)
- {
- $decimal = str_pad($decimal, $decimalDigits, '0');
- }
- else
- {
- $decimal = substr($float, strpos($float,'.') + 1);
- if (strlen($decimal)<$decimalDigits)
- {
- $decimal = str_pad($decimal, $decimalDigits, '0');
- }
- }
- }
- else
- {
- return $decimal;
- }
- return $decimalSeparator.$decimal;
- }
- else if ($decimalDigits > 0)
- {
- return $decimalSeparator.str_pad($decimal, $decimalDigits, '0');
- }
- return $decimal;
- }
- /**
- * Sets the pattern to format against. The default patterns
- * are retrieved from the sfNumberFormatInfo instance.
- *
- * @param string $pattern the requested patterns.
- * @return string a number format pattern.
- */
- protected function setPattern($pattern)
- {
- switch ($pattern)
- {
- case 'c':
- case 'C':
- $this->formatInfo->setPattern(sfNumberFormatInfo::CURRENCY);
- break;
- case 'd':
- case 'D':
- $this->formatInfo->setPattern(sfNumberFormatInfo::DECIMAL);
- break;
- case 'e':
- case 'E':
- $this->formatInfo->setPattern(sfNumberFormatInfo::SCIENTIFIC);
- break;
- case 'p':
- case 'P':
- $this->formatInfo->setPattern(sfNumberFormatInfo::PERCENTAGE);
- break;
- default:
- $this->formatInfo->setPattern($pattern);
- break;
- }
- }
- }
|