PageRenderTime 26ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/standard/tags/release-1.5.0PR/library/Zend/Measure/Number.php

https://github.com/bhaumik25/zend-framework
PHP | 391 lines | 268 code | 43 blank | 80 comment | 31 complexity | 9ff99572b8125a57f741240d9ec0453b MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Measure
  17. * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @version $Id$
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /**
  22. * Implement needed classes
  23. */
  24. require_once 'Zend/Measure/Abstract.php';
  25. require_once 'Zend/Locale.php';
  26. /**
  27. * @category Zend
  28. * @package Zend_Measure
  29. * @subpackage Zend_Measure_Number
  30. * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
  31. * @license http://framework.zend.com/license/new-bsd New BSD License
  32. *
  33. * This class can only handle numbers without precission
  34. */
  35. class Zend_Measure_Number extends Zend_Measure_Abstract
  36. {
  37. // Number definitions
  38. const STANDARD = 'DECIMAL';
  39. const BINARY = 'BINARY';
  40. const TERNARY = 'TERNARY';
  41. const QUATERNARY = 'QUATERNARY';
  42. const QUINARY = 'QUINARY';
  43. const SENARY = 'SENARY';
  44. const SEPTENARY = 'SEPTENARY';
  45. const OCTAL = 'OCTAL';
  46. const NONARY = 'NONARY';
  47. const DECIMAL = 'DECIMAL';
  48. const DUODECIMAL = 'DUODECIMAL';
  49. const HEXADECIMAL = 'HEXADECIMAL';
  50. const ROMAN = 'ROMAN';
  51. protected $_UNITS = array(
  52. 'BINARY' => array(2, '⑵'),
  53. 'TERNARY' => array(3, '⑶'),
  54. 'QUATERNARY' => array(4, '⑷'),
  55. 'QUINARY' => array(5, '⑸'),
  56. 'SENARY' => array(6, '⑹'),
  57. 'SEPTENARY' => array(7, '⑺'),
  58. 'OCTAL' => array(8, '⑻'),
  59. 'NONARY' => array(9, '⑼'),
  60. 'DECIMAL' => array(10, '⑽'),
  61. 'DUODECIMAL' => array(12, '⑿'),
  62. 'HEXADECIMAL' => array(16, '⒃'),
  63. 'ROMAN' => array(99, ''),
  64. 'STANDARD' => 'DECIMAL'
  65. );
  66. // Definition of all roman signs
  67. private static $_ROMAN = array(
  68. 'I' => 1,
  69. 'A' => 4,
  70. 'V' => 5,
  71. 'B' => 9,
  72. 'X' => 10,
  73. 'E' => 40,
  74. 'L' => 50,
  75. 'F' => 90,
  76. 'C' => 100,
  77. 'G' => 400,
  78. 'D' => 500,
  79. 'H' => 900,
  80. 'M' => 1000,
  81. 'J' => 4000,
  82. 'P' => 5000,
  83. 'K' => 9000,
  84. 'Q' => 10000,
  85. 'N' => 40000,
  86. 'R' => 50000,
  87. 'W' => 90000,
  88. 'S' => 100000,
  89. 'Y' => 400000,
  90. 'T' => 500000,
  91. 'Z' => 900000,
  92. 'U' => 1000000
  93. );
  94. // Convertion table for roman signs
  95. private static $_ROMANCONVERT = array(
  96. '/_V/' => '/P/',
  97. '/_X/' => '/Q/',
  98. '/_L/' => '/R/',
  99. '/_C/' => '/S/',
  100. '/_D/' => '/T/',
  101. '/_M/' => '/U/',
  102. '/IV/' => '/A/',
  103. '/IX/' => '/B/',
  104. '/XL/' => '/E/',
  105. '/XC/' => '/F/',
  106. '/CD/' => '/G/',
  107. '/CM/' => '/H/',
  108. '/M_V/'=> '/J/',
  109. '/MQ/' => '/K/',
  110. '/QR/' => '/N/',
  111. '/QS/' => '/W/',
  112. '/ST/' => '/Y/',
  113. '/SU/' => '/Z/'
  114. );
  115. /**
  116. * Zend_Measure_Abstract is an abstract class for the different measurement types
  117. *
  118. * @param $value mixed - Value as string, integer, real or float
  119. * @param $type type - OPTIONAL a Zend_Measure_Area Type
  120. * @param $locale locale - OPTIONAL a Zend_Locale Type
  121. * @throws Zend_Measure_Exception
  122. */
  123. public function __construct($value, $type, $locale = null)
  124. {
  125. if (Zend_Locale::isLocale($type)) {
  126. $locale = $type;
  127. $type = null;
  128. }
  129. if ($locale === null) {
  130. $locale = new Zend_Locale();
  131. }
  132. if ($locale instanceof Zend_Locale) {
  133. $locale = $locale->toString();
  134. }
  135. if (!$this->_Locale = Zend_Locale::isLocale($locale, true)) {
  136. require_once 'Zend/Measure/Exception.php';
  137. throw new Zend_Measure_Exception("Language ($locale) is unknown");
  138. }
  139. $this->_Locale = $locale;
  140. if ($type === null) {
  141. $type = $this->_UNITS['STANDARD'];
  142. }
  143. if (!array_key_exists($type, $this->_UNITS)) {
  144. require_once 'Zend/Measure/Exception.php';
  145. throw new Zend_Measure_Exception("Type ($type) is unknown");
  146. }
  147. $this->setValue($value, $type, $this->_Locale);
  148. }
  149. /**
  150. * Set a new value
  151. *
  152. * @param $value mixed - Value as string, integer, real or float
  153. * @param $type type - OPTIONAL a Zend_Measure_Number Type
  154. * @param $locale locale - OPTIONAL a Zend_Locale Type
  155. * @throws Zend_Measure_Exception
  156. */
  157. public function setValue($value, $type = null, $locale = null)
  158. {
  159. if (empty( $locale )) {
  160. $locale = $this->_Locale;
  161. }
  162. if (empty($this->_UNITS[$type])) {
  163. require_once 'Zend/Measure/Exception.php';
  164. throw new Zend_Measure_Exception('unknown type of number:' . $type);
  165. }
  166. switch( $type ) {
  167. case 'BINARY' :
  168. preg_match('/[01]+/', $value, $ergebnis);
  169. $value = $ergebnis[0];
  170. break;
  171. case 'TERNARY' :
  172. preg_match('/[012]+/', $value, $ergebnis);
  173. $value = $ergebnis[0];
  174. break;
  175. case 'QUATERNARY' :
  176. preg_match('/[0123]+/', $value, $ergebnis);
  177. $value = $ergebnis[0];
  178. break;
  179. case 'QUINARY' :
  180. preg_match('/[01234]+/', $value, $ergebnis);
  181. $value = $ergebnis[0];
  182. break;
  183. case 'SENARY' :
  184. preg_match('/[012345]+/', $value, $ergebnis);
  185. $value = $ergebnis[0];
  186. break;
  187. case 'SEPTENARY' :
  188. preg_match('/[0123456]+/', $value, $ergebnis);
  189. $value = $ergebnis[0];
  190. break;
  191. case 'OCTAL' :
  192. preg_match('/[01234567]+/', $value, $ergebnis);
  193. $value = $ergebnis[0];
  194. break;
  195. case 'NONARY' :
  196. preg_match('/[012345678]+/', $value, $ergebnis);
  197. $value = $ergebnis[0];
  198. break;
  199. case 'DUODECIMAL' :
  200. preg_match('/[0123456789AB]+/', strtoupper( $value ), $ergebnis);
  201. $value = $ergebnis[0];
  202. break;
  203. case 'HEXADECIMAL' :
  204. preg_match('/[0123456789ABCDEF]+/', strtoupper( $value ), $ergebnis);
  205. $value = $ergebnis[0];
  206. break;
  207. case 'ROMAN' :
  208. preg_match('/[IVXLCDM_]+/', strtoupper( $value ), $ergebnis);
  209. $value = $ergebnis[0];
  210. break;
  211. default:
  212. try {
  213. $value = Zend_Locale_Format::getInteger($value, array('locale' => $locale));
  214. } catch (Exception $e) {
  215. require_once 'Zend/Measure/Exception.php';
  216. throw new Zend_Measure_Exception($e->getMessage());
  217. }
  218. preg_match('/[0123456789]+/', $value, $ergebnis);
  219. $value = $ergebnis[0];
  220. break;
  221. }
  222. $this->_value = $value;
  223. $this->_type = $type;
  224. }
  225. /**
  226. * Convert input to decimal value string
  227. *
  228. * @param $input mixed - input string
  229. * @param $type type - type from which to convert to decimal
  230. * @return string
  231. */
  232. private function toDecimal($input, $type)
  233. {
  234. $value = "";
  235. // Convert base xx values
  236. if ($this->_UNITS[$type][0] <= 16) {
  237. $split = str_split( $input );
  238. $length = strlen( $input );
  239. for($X = 0; $X < $length; ++$X) {
  240. $split[$X] = hexdec( $split[$X] );
  241. $value = call_user_func(Zend_Locale_Math::$add, $value,
  242. call_user_func(Zend_Locale_Math::$mul, $split[$X],
  243. call_user_func(Zend_Locale_Math::$pow, $this->_UNITS[$type][0], ($length - $X - 1))));
  244. }
  245. }
  246. // Convert roman numbers
  247. if ($type == 'ROMAN') {
  248. $input = strtoupper( $input );
  249. $input = preg_replace( array_keys(self::$_ROMANCONVERT), array_values(self::$_ROMANCONVERT), $input);
  250. $split = preg_split('//', strrev($input), -1, PREG_SPLIT_NO_EMPTY);
  251. for ($X=0; $X < sizeof($split); $X++) {
  252. if ($split[$X] == '/') {
  253. continue;
  254. }
  255. $num = self::$_ROMAN[$split[$X]];
  256. if (($X > 0 and ($split[$X-1] != '/') and ($num < self::$_ROMAN[$split[$X-1]]))) {
  257. $num -= $num;
  258. }
  259. $value += $num;
  260. }
  261. str_replace('/', '', $value);
  262. }
  263. return $value;
  264. }
  265. /**
  266. * Convert input to type value string
  267. *
  268. * @param $input mixed - input string
  269. * @param $type type - type to convert to
  270. * @return string
  271. */
  272. private function fromDecimal($value, $type)
  273. {
  274. $tempvalue = $value;
  275. if ($this->_UNITS[$type][0] <= 16) {
  276. $newvalue = "";
  277. $count = 200;
  278. while (call_user_func(Zend_Locale_Math::$comp, $value, 0, 25) <> 0) {
  279. $target = call_user_func(Zend_Locale_Math::$mod, $value, $this->_UNITS[$type][0]);
  280. $target = strtoupper( dechex($target) );
  281. $newvalue = $target . $newvalue;
  282. $value = call_user_func(Zend_Locale_Math::$div, $value, $this->_UNITS[$type][0], 0);
  283. if (($value == 1) and ($newvalue == 1)) {
  284. break;
  285. }
  286. --$count;
  287. if ($count == 0) {
  288. require_once 'Zend/Measure/Exception.php';
  289. throw new Zend_Measure_Exception("Your value '$tempvalue' cannot be processed because it extends 200 digits");
  290. }
  291. }
  292. }
  293. if ($type == 'ROMAN') {
  294. $i = 0;
  295. $newvalue = "";
  296. $romanval = array_values( array_reverse(self::$_ROMAN) );
  297. $romankey = array_keys( array_reverse(self::$_ROMAN) );
  298. $count = 200;
  299. while(call_user_func(Zend_Locale_Math::$comp, $value, 0, 25) <> 0) {
  300. while ($value >= $romanval[$i]) {
  301. $value -= $romanval[$i];
  302. $newvalue .= $romankey[$i];
  303. if ($value < 1) {
  304. break;
  305. }
  306. --$count;
  307. if ($count == 0) {
  308. require_once 'Zend/Measure/Exception.php';
  309. throw new Zend_Measure_Exception("Your value '$tempvalue' cannot be processed because it extends 200 digits");
  310. }
  311. }
  312. $i++;
  313. }
  314. $newvalue = str_replace("/", "", preg_replace(array_values(self::$_ROMANCONVERT), array_keys(self::$_ROMANCONVERT), $newvalue));
  315. }
  316. return $newvalue;
  317. }
  318. /**
  319. * Set a new type, and convert the value
  320. *
  321. * @param $type new type to set
  322. * @throws Zend_Measure_Exception
  323. */
  324. public function setType( $type )
  325. {
  326. if (empty($this->_UNITS[$type])) {
  327. require_once 'Zend/Measure/Exception.php';
  328. throw new Zend_Measure_Exception('Unknown type of number:' . $type);
  329. }
  330. $value = $this->toDecimal($this->getValue(-1), $this->getType(-1));
  331. $value = $this->fromDecimal($value, $type);
  332. $this->_value = $value;
  333. $this->_type = $type;
  334. }
  335. /**
  336. * Alias function for setType returning the converted unit
  337. * Default is 0 as this class only handles numbers without precision
  338. *
  339. * @param $type type
  340. * @param $round integer OPTIONAL Precision to add, will always be 0
  341. * @return string
  342. */
  343. public function convertTo($type, $round = 0)
  344. {
  345. $this->setType($type);
  346. return $this->toString($round);
  347. }
  348. }