/standard/tags/release-1.5.2/library/Zend/Measure/Number.php
PHP | 398 lines | 270 code | 48 blank | 80 comment | 31 complexity | 344cb825ee583fc13e401545c623f42a MD5 | raw file
- <?php
- /**
- * Zend Framework
- *
- * LICENSE
- *
- * This source file is subject to the new BSD license that is bundled
- * with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://framework.zend.com/license/new-bsd
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@zend.com so we can send you a copy immediately.
- *
- * @category Zend
- * @package Zend_Measure
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
- * @version $Id$
- * @license http://framework.zend.com/license/new-bsd New BSD License
- */
- /**
- * Implement needed classes
- */
- require_once 'Zend/Measure/Abstract.php';
- require_once 'Zend/Locale.php';
- /**
- * @category Zend
- * @package Zend_Measure
- * @subpackage Zend_Measure_Number
- * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- *
- * This class can only handle numbers without precission
- */
- class Zend_Measure_Number extends Zend_Measure_Abstract
- {
- // Number definitions
- const STANDARD = 'DECIMAL';
- const BINARY = 'BINARY';
- const TERNARY = 'TERNARY';
- const QUATERNARY = 'QUATERNARY';
- const QUINARY = 'QUINARY';
- const SENARY = 'SENARY';
- const SEPTENARY = 'SEPTENARY';
- const OCTAL = 'OCTAL';
- const NONARY = 'NONARY';
- const DECIMAL = 'DECIMAL';
- const DUODECIMAL = 'DUODECIMAL';
- const HEXADECIMAL = 'HEXADECIMAL';
- const ROMAN = 'ROMAN';
- protected $_UNITS = array(
- 'BINARY' => array(2, '⑵'),
- 'TERNARY' => array(3, '⑶'),
- 'QUATERNARY' => array(4, '⑷'),
- 'QUINARY' => array(5, '⑸'),
- 'SENARY' => array(6, '⑹'),
- 'SEPTENARY' => array(7, '⑺'),
- 'OCTAL' => array(8, '⑻'),
- 'NONARY' => array(9, '⑼'),
- 'DECIMAL' => array(10, '⑽'),
- 'DUODECIMAL' => array(12, '⑿'),
- 'HEXADECIMAL' => array(16, '⒃'),
- 'ROMAN' => array(99, ''),
- 'STANDARD' => 'DECIMAL'
- );
- // Definition of all roman signs
- private static $_ROMAN = array(
- 'I' => 1,
- 'A' => 4,
- 'V' => 5,
- 'B' => 9,
- 'X' => 10,
- 'E' => 40,
- 'L' => 50,
- 'F' => 90,
- 'C' => 100,
- 'G' => 400,
- 'D' => 500,
- 'H' => 900,
- 'M' => 1000,
- 'J' => 4000,
- 'P' => 5000,
- 'K' => 9000,
- 'Q' => 10000,
- 'N' => 40000,
- 'R' => 50000,
- 'W' => 90000,
- 'S' => 100000,
- 'Y' => 400000,
- 'T' => 500000,
- 'Z' => 900000,
- 'U' => 1000000
- );
- // Convertion table for roman signs
- private static $_ROMANCONVERT = array(
- '/_V/' => '/P/',
- '/_X/' => '/Q/',
- '/_L/' => '/R/',
- '/_C/' => '/S/',
- '/_D/' => '/T/',
- '/_M/' => '/U/',
- '/IV/' => '/A/',
- '/IX/' => '/B/',
- '/XL/' => '/E/',
- '/XC/' => '/F/',
- '/CD/' => '/G/',
- '/CM/' => '/H/',
- '/M_V/'=> '/J/',
- '/MQ/' => '/K/',
- '/QR/' => '/N/',
- '/QS/' => '/W/',
- '/ST/' => '/Y/',
- '/SU/' => '/Z/'
- );
- /**
- * Zend_Measure_Abstract is an abstract class for the different measurement types
- *
- * @param $value mixed - Value as string, integer, real or float
- * @param $type type - OPTIONAL a Zend_Measure_Area Type
- * @param $locale locale - OPTIONAL a Zend_Locale Type
- * @throws Zend_Measure_Exception
- */
- public function __construct($value, $type, $locale = null)
- {
- if (Zend_Locale::isLocale($type)) {
- $locale = $type;
- $type = null;
- }
- if ($locale === null) {
- $locale = new Zend_Locale();
- }
- if ($locale instanceof Zend_Locale) {
- $locale = $locale->toString();
- }
- if (!$this->_Locale = Zend_Locale::isLocale($locale, true)) {
- require_once 'Zend/Measure/Exception.php';
- throw new Zend_Measure_Exception("Language ($locale) is unknown");
- }
- $this->_Locale = $locale;
- if ($type === null) {
- $type = $this->_UNITS['STANDARD'];
- }
- if (!array_key_exists($type, $this->_UNITS)) {
- require_once 'Zend/Measure/Exception.php';
- throw new Zend_Measure_Exception("Type ($type) is unknown");
- }
- $this->setValue($value, $type, $this->_Locale);
- }
- /**
- * Set a new value
- *
- * @param $value mixed - Value as string, integer, real or float
- * @param $type type - OPTIONAL a Zend_Measure_Number Type
- * @param $locale locale - OPTIONAL a Zend_Locale Type
- * @throws Zend_Measure_Exception
- */
- public function setValue($value, $type = null, $locale = null)
- {
- if (empty( $locale )) {
- $locale = $this->_Locale;
- }
- if (empty($this->_UNITS[$type])) {
- require_once 'Zend/Measure/Exception.php';
- throw new Zend_Measure_Exception('unknown type of number:' . $type);
- }
- switch( $type ) {
- case 'BINARY' :
- preg_match('/[01]+/', $value, $ergebnis);
- $value = $ergebnis[0];
- break;
- case 'TERNARY' :
- preg_match('/[012]+/', $value, $ergebnis);
- $value = $ergebnis[0];
- break;
- case 'QUATERNARY' :
- preg_match('/[0123]+/', $value, $ergebnis);
- $value = $ergebnis[0];
- break;
- case 'QUINARY' :
- preg_match('/[01234]+/', $value, $ergebnis);
- $value = $ergebnis[0];
- break;
- case 'SENARY' :
- preg_match('/[012345]+/', $value, $ergebnis);
- $value = $ergebnis[0];
- break;
- case 'SEPTENARY' :
- preg_match('/[0123456]+/', $value, $ergebnis);
- $value = $ergebnis[0];
- break;
- case 'OCTAL' :
- preg_match('/[01234567]+/', $value, $ergebnis);
- $value = $ergebnis[0];
- break;
- case 'NONARY' :
- preg_match('/[012345678]+/', $value, $ergebnis);
- $value = $ergebnis[0];
- break;
- case 'DUODECIMAL' :
- preg_match('/[0123456789AB]+/', strtoupper( $value ), $ergebnis);
- $value = $ergebnis[0];
- break;
- case 'HEXADECIMAL' :
- preg_match('/[0123456789ABCDEF]+/', strtoupper( $value ), $ergebnis);
- $value = $ergebnis[0];
- break;
- case 'ROMAN' :
- preg_match('/[IVXLCDM_]+/', strtoupper( $value ), $ergebnis);
- $value = $ergebnis[0];
- break;
- default:
- try {
- $value = Zend_Locale_Format::getInteger($value, array('locale' => $locale));
- } catch (Exception $e) {
- require_once 'Zend/Measure/Exception.php';
- throw new Zend_Measure_Exception($e->getMessage());
- }
- if (call_user_func(Zend_Locale_Math::$comp, $value, 0) < 0) {
- $value = call_user_func(Zend_Locale_Math::$sqrt, call_user_func(Zend_Locale_Math::$pow, $value, 2));
- }
- break;
- }
- $this->_value = $value;
- $this->_type = $type;
- }
- /**
- * Convert input to decimal value string
- *
- * @param $input mixed - input string
- * @param $type type - type from which to convert to decimal
- * @return string
- */
- private function toDecimal($input, $type)
- {
- $value = "";
- // Convert base xx values
- if ($this->_UNITS[$type][0] <= 16) {
- $split = str_split( $input );
- $length = strlen( $input );
- for($X = 0; $X < $length; ++$X) {
- $split[$X] = hexdec( $split[$X] );
- $value = call_user_func(Zend_Locale_Math::$add, $value,
- call_user_func(Zend_Locale_Math::$mul, $split[$X],
- call_user_func(Zend_Locale_Math::$pow, $this->_UNITS[$type][0], ($length - $X - 1))));
- }
- }
- // Convert roman numbers
- if ($type == 'ROMAN') {
- $input = strtoupper( $input );
- $input = preg_replace( array_keys(self::$_ROMANCONVERT), array_values(self::$_ROMANCONVERT), $input);
- $split = preg_split('//', strrev($input), -1, PREG_SPLIT_NO_EMPTY);
- for ($X=0; $X < sizeof($split); $X++) {
- if ($split[$X] == '/') {
- continue;
- }
- $num = self::$_ROMAN[$split[$X]];
- if (($X > 0 and ($split[$X-1] != '/') and ($num < self::$_ROMAN[$split[$X-1]]))) {
- $num -= $num;
- }
- $value += $num;
- }
- str_replace('/', '', $value);
- }
- return $value;
- }
- /**
- * Convert input to type value string
- *
- * @param $input mixed - input string
- * @param $type type - type to convert to
- * @return string
- */
- private function fromDecimal($value, $type)
- {
- $tempvalue = $value;
- if ($this->_UNITS[$type][0] <= 16) {
- $newvalue = '';
- $count = 200;
- $base = $this->_UNITS[$type][0];
-
- while (call_user_func(Zend_Locale_Math::$comp, $value, 0, 25) <> 0) {
- $target = call_user_func(Zend_Locale_Math::$mod, $value, $base);
-
- $newvalue = strtoupper( dechex($target) ) . $newvalue;
-
- $value = call_user_func(Zend_Locale_Math::$sub, $value, $target, 0);
- $value = call_user_func(Zend_Locale_Math::$div, $value, $base, 0);
-
- --$count;
- if ($count == 0) {
- require_once 'Zend/Measure/Exception.php';
- throw new Zend_Measure_Exception("Your value '$tempvalue' cannot be processed because it extends 200 digits");
- }
- }
-
- if ($newvalue == '') {
- $newvalue = '0';
- }
- }
- if ($type == 'ROMAN') {
- $i = 0;
- $newvalue = "";
- $romanval = array_values( array_reverse(self::$_ROMAN) );
- $romankey = array_keys( array_reverse(self::$_ROMAN) );
- $count = 200;
- while(call_user_func(Zend_Locale_Math::$comp, $value, 0, 25) <> 0) {
- while ($value >= $romanval[$i]) {
- $value -= $romanval[$i];
- $newvalue .= $romankey[$i];
- if ($value < 1) {
- break;
- }
- --$count;
- if ($count == 0) {
- require_once 'Zend/Measure/Exception.php';
- throw new Zend_Measure_Exception("Your value '$tempvalue' cannot be processed because it extends 200 digits");
- }
- }
- $i++;
- }
- $newvalue = str_replace("/", "", preg_replace(array_values(self::$_ROMANCONVERT), array_keys(self::$_ROMANCONVERT), $newvalue));
- }
- return $newvalue;
- }
- /**
- * Set a new type, and convert the value
- *
- * @param $type new type to set
- * @throws Zend_Measure_Exception
- */
- public function setType( $type )
- {
- if (empty($this->_UNITS[$type])) {
- require_once 'Zend/Measure/Exception.php';
- throw new Zend_Measure_Exception('Unknown type of number:' . $type);
- }
- $value = $this->toDecimal($this->getValue(-1), $this->getType(-1));
- $value = $this->fromDecimal($value, $type);
- $this->_value = $value;
- $this->_type = $type;
- }
- /**
- * Alias function for setType returning the converted unit
- * Default is 0 as this class only handles numbers without precision
- *
- * @param $type type
- * @param $round integer OPTIONAL Precision to add, will always be 0
- * @return string
- */
- public function convertTo($type, $round = 0)
- {
- $this->setType($type);
- return $this->toString($round);
- }
- }