NumberFormatter

The Inline Google Spreadsheet Viewer NumberFormatter class.

Defined (1)

The class is defined in the following location(s).

/lib/visformat.php  
  1. class NumberFormatter { 
  2. private $pos_format; 
  3. private $neg_format; 
  4.  
  5. private $decimal_sep; 
  6. private $group_sep; 
  7. private $exponent_string; 
  8. private $negative_prefix; 
  9. private $positive_prefix; 
  10. private $def_first_group; 
  11. private $def_other_group; 
  12.  
  13. const PATTERN_DECIMAL = 1; 
  14.  
  15. public function __construct($locale, $style, $format) { 
  16. $lsave = setlocale(LC_ALL, "0"); 
  17.  
  18. $this->def_first_group = 3; 
  19. $this->decimal_sep = '.'; 
  20. $this->group_sep = ', '; 
  21. $this->exponent_string = "E"; 
  22. $this->negative_prefix = "-"; 
  23. $this->positive_prefix = "+"; 
  24.  
  25. $loc = setlocale(LC_ALL, $locale); 
  26. if ($loc) { 
  27. $info = localeconv(); 
  28.  
  29. $this->decimal_sep = $info['decimal_point']; 
  30. $this->group_sep = $info['thousands_sep']; 
  31. // $this->negative_prefix = $info['negative_sign']; 
  32. // $this->positive_prefix = $info['positive_sign']; 
  33.  
  34. setlocale(LC_ALL, $lsave); 
  35.  
  36. $fmts = explode(";", $format); 
  37. if (!isset($fmts[1])) { 
  38. $fmts[1] = $this->negative_prefix.$fmts[0]; 
  39.  
  40. $neg = $this->parsefmt($fmts[1]); 
  41. $this->pos_format = $this->parsefmt($fmts[0]); 
  42.  
  43. $neg2 = $this->pos_format; 
  44. $neg2[0] = $neg[0]; 
  45. $neg2[3] = $neg[3]; 
  46. $this->neg_format = $neg2; 
  47.  
  48. // print_r($this); 
  49.  
  50. private function parsefmt($fmt) 
  51. $parts = array("", "", "", ""); 
  52. $inquote = FALSE; 
  53. $state = 0; 
  54. for ($start = 0; ($ch = substr($fmt, $start, 1)) !== FALSE; $start++) { 
  55. switch ($state) { 
  56. case '0': 
  57. case '3': 
  58. $is_special = strpos("0123456789@#., ", $ch) !== FALSE; 
  59. if ($ch == '*') { 
  60. $parts['pad'] = substr($fmt, ++$start, 1); 
  61. $parts['pad_pos'] = $state ^ ($parts[$state] !== ""?1:0); 
  62. if ($parts[$state] !== "") { 
  63. $state++; 
  64. } else if ($ch == "'") { 
  65. if (substr($fmt, $start+1, 1) == "'") { 
  66. $parts[$state] .= "'"; 
  67. $start += 1; 
  68. } else { 
  69. $inquote = !$inquote; 
  70. } else if ($inquote || !$is_special) { 
  71. $parts[$state] .= $ch; 
  72. } else { 
  73. $start--; 
  74. $state++; 
  75. break; 
  76. case '1': 
  77. if (preg_match("/^([#, ]*[0-9, ]+(\.0*#*)?|[#, ]*[@, ]+[#, ]*)/", substr($fmt, $start), $matches)) { 
  78. $parts[1] = $matches[1]; 
  79. $start += strlen($matches[1]) - 1; 
  80. $state++; 
  81. } else { 
  82. $this->error = "Missing Number in format"; 
  83. break; 
  84. case 2: 
  85. if (preg_match("/^(E(\+?)(0+))?/", substr($fmt, $start), $matches)) { 
  86. $parts[2] = $matches[1]; 
  87. $parts['exp_fmt'] = "%{$matches[2]}0".strlen($matches[2].$matches[3])."d"; 
  88. $start += strlen($matches[1]); 
  89. $state++; 
  90. $start--; 
  91. break; 
  92. case 4: 
  93. $this->error = "Unexpected text following suffix"; 
  94. break; 
  95. }  
  96.  
  97. $parts["format_width"] = strlen($parts[0].$parts[1].$parts[2].$parts[3]); 
  98.  
  99. if (strpos($parts[0].$parts[3], "%") !== FALSE) { 
  100. $parts["multiplier"] = 100; 
  101. if (strpos($parts[0].$parts[3], "\u2030") !== FALSE) { 
  102. $parts["multiplier"] = 1000; 
  103.  
  104. $rep = ""; 
  105. $commas = array(); 
  106. for ($i = 0; ($ch = substr($parts[1], $i, 1)) !== FALSE; $i++) { 
  107. if ($ch == ', ') { 
  108. $commas[] = $i; 
  109. } else if ($ch == '.') { 
  110. $rep .= substr($parts[1], $i); 
  111. break; 
  112. } else { 
  113. $rep .= $ch; 
  114. $at = strpos($rep, "@"); 
  115. if ($at !== FALSE) { 
  116. // strip leading "#" chars. 
  117. $rep = substr($rep, $at); 
  118. $max = strlen($rep); 
  119. $min = strpos($rep, "#"); 
  120. if ($min === FALSE) $min = $max; 
  121. $parts['sigmax'] = $max; 
  122. $parts['sigmin'] = $min; 
  123. } else { 
  124. $z = strpos($rep, '0'); 
  125. $d = strpos($rep, '.'); 
  126. if ($d === FALSE) $d = strlen($rep); 
  127.  
  128. $min_int = $d - $z; 
  129. $max_int = $d; 
  130. $max_flt = strlen(substr($rep, $d+1)); 
  131. $min_flt = strpos(substr($rep, $d+1), "#"); 
  132. if ($min_flt === FALSE) { 
  133. $min_flt = $max_flt; 
  134. $parts['min_int'] = $min_int; 
  135. $parts['max_int'] = $max_int; 
  136. $parts['min_flt'] = $min_flt; 
  137. $parts['max_flt'] = $max_flt; 
  138. $parts[1] = $rep; 
  139. $len = count($commas); 
  140. if ($len) { 
  141. $parts['first_group'] = $i - $commas[$len-1] - 1; 
  142. if ($len > 1) { 
  143. $parts['second_group'] = $commas[$len-1] - $commas[$len-2] - 1; 
  144. } else if ($parts['first_group'] == 0) { 
  145. $parts['first_group'] = $this->def_first_group; 
  146. if (isset($this->def_other_group)) { 
  147. $parts['second_group'] = $this->def_other_group; 
  148. return $parts; 
  149.  
  150. public function format($number) 
  151. if ($number < 0) { 
  152. $format = $this->neg_format; 
  153. $number = -$number; 
  154. } else { 
  155. $format = $this->pos_format; 
  156.  
  157. if ($format['multiplier']) { 
  158. $number *= $format['multiplier']; 
  159. if ($format[2]) { 
  160. $exp_group = 1; 
  161. if (isset($format['sigmax'])) { 
  162. $max_int = $min_int = 1; 
  163. $max_flt = $min_flt = $format['sigmax'] - 1; 
  164. } else { 
  165. $min_int = $format['min_int']; 
  166. $max_int = $format['max_int']; 
  167. $min_flt = $format['min_flt']; 
  168. $max_flt = $format['max_flt']; 
  169. if ($max_int > $min_int) { 
  170. $min_int = 1; 
  171. $exp_group = $max_int; 
  172. $dig = $min_int + $max_flt - 1; 
  173. $s = sprintf("%.{$dig}e", $number); 
  174. if (preg_match("/^([0-9]+)\.([0-9]*)E(.*)$/i", $s, $matches)) { 
  175. $intval = $matches[1].$matches[2]; 
  176. $exp = intval($matches[3]) + strlen($matches[1]) - $min_int; 
  177. $adj = $exp % $exp_group; 
  178. $split = $min_int; 
  179. if ($adj < 0) { 
  180. $adj = $exp_group + $adj; 
  181. $split += $adj; 
  182. $exp -= $adj; 
  183.  
  184. $int = substr($intval, 0, $split); 
  185. $flt = substr($intval, $split); 
  186.  
  187. while (substr($flt, -1) == "0" && strlen($flt) > $min_flt) { 
  188. $flt = substr($flt, 0, -1); 
  189. $e = sprintf($format['exp_fmt'], $exp); 
  190. $sgn = substr($e, 0, 1); 
  191. if ($sgn == '+' || $sgn == '-') { 
  192. $e = ($sgn == '+' ? $this->positive_prefix : $this->negative_prefix). 
  193. substr($e, 1); 
  194. $s = "$int.$flt".$this->exponent_string.$e; 
  195. } else if (isset($format['sigmax'])) { 
  196. $dig = strlen($format[1])-1; 
  197. $s = sprintf("%.{$dig}e", $number); 
  198. $max = $format['sigmax']; 
  199. $min = $format['sigmin']; 
  200. if (preg_match("/^([0-9])\.([0-9]*)E(.*)$/i", $s, $matches)) { 
  201. $intval = $matches[1].$matches[2]; 
  202. $exp = intval($matches[3])+1; 
  203. $len = strlen($intval); 
  204. while ($len > $min && substr($intval, -1)=='0') { 
  205. $intval = substr($intval, 0, --$len); 
  206. if ($exp >= $len) { 
  207. $intval = str_pad($intval, $exp, "0"); 
  208. } else if ($exp < 0) { 
  209. $intval = "0." + str_pad("", -$exp, "0").$intval; 
  210. } else { 
  211. $intval = substr($intval, 0, $exp).".".substr($intval, $exp); 
  212. $s = $intval; 
  213. } else { 
  214. $min_int = $format['min_int']; 
  215. $max_int = $format['max_int']; 
  216. $min_flt = $format['min_flt']; 
  217. $max_flt = $format['max_flt']; 
  218.  
  219. $s = sprintf("%.{$max_flt}F", $number); 
  220. $d = strpos($s, "."); 
  221. if ($d === FALSE) $d = strlen($s); 
  222. if ($d < min_int) { 
  223. $s = str_pad("", $min_int - $d, "0").$s; 
  224. while (substr($s, -1) == "0" && strlen($s)-$d-1 > $min_flt) { 
  225. $s = substr($s, 0, -1); 
  226. $d = strpos($s, "."); 
  227. if ($d === FALSE) { 
  228. $t = $s; 
  229. $s = ""; 
  230. } else { 
  231. $t = substr($s, 0, $d); 
  232. $s = $this->decimal_sep . substr($s, $d + 1); 
  233. if (isset($format["first_group"])) { 
  234. $g = $format["first_group"]; 
  235. $g2 = isset($format["second_group"]) ? $format["second_group"] : $g; 
  236. while (strlen($t) > $g) { 
  237. $s = $this->group_sep . substr($t, -$g) . $s; 
  238. $t = substr($t, 0, -$g); 
  239. $g = $g2; 
  240. $s = $t . $s; 
  241. $t = $format[0] . $s . $format[3]; 
  242. $len = strlen($t); 
  243. if (isset($format['pad'])) { 
  244. $plen = $format['format_width']; 
  245. if ($plen > $len) { 
  246. $pad = str_pad("", $plen - $len, $format['pad']); 
  247. if (!($format['pad_pos'] & 1)) { 
  248. $s = $t; 
  249. if ($format['pad_pos'] & 2) { 
  250. $s = $s.$pad; 
  251. } else { 
  252. $s = $pad.$s; 
  253. if ($format['pad_pos'] & 1) { 
  254. $s = $format[0] . $s . $format[3]; 
  255. } else { 
  256. $s = $t; 
  257. } else { 
  258. $s = $t; 
  259.  
  260. return $s; 
  261. };