PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/i18n/sfChoiceFormat.class.php

https://github.com/theodo/symfony1.0-backports
PHP | 212 lines | 106 code | 21 blank | 85 comment | 33 complexity | b15b0534f1f19a5859f56a7df5bf2901 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0, BSD-3-Clause
  1. <?php
  2. /**
  3. * sfChoiceFormat class file.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the BSD License.
  7. *
  8. * Copyright(c) 2004 by Qiang Xue. All rights reserved.
  9. *
  10. * To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
  11. * The latest version of PRADO can be obtained from:
  12. * {@link http://prado.sourceforge.net/}
  13. *
  14. * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
  15. * @version $Id$
  16. * @package symfony
  17. * @subpackage i18n
  18. */
  19. /**
  20. * sfChoiceFormat class.
  21. *
  22. * sfChoiceFormat converts between ranges of numeric values and string
  23. * names for those ranges.
  24. *
  25. * A sfChoiceFormat splits the real number line -Inf to +Inf into two or
  26. * more contiguous ranges. Each range is mapped to a string.
  27. * sfChoiceFormat is generally used in a MessageFormat for displaying
  28. * grammatically correct plurals such as "There are 2 files."
  29. *
  30. * <code>
  31. * $string = '[0] are no files |[1] is one file |(1,Inf] are {number} files';
  32. *
  33. * $formatter = new sfMessageFormat(...); //init for a source
  34. * $translated = $formatter->format($string);
  35. *
  36. * $choice = new sfChoiceFormat();
  37. * echo $choice->format($translated, 0); //shows "are no files"
  38. * </code>
  39. *
  40. * The message/string choices are separated by the pipe "|" followed
  41. * by a set notation of the form
  42. * # <t>[1,2]</t> -- accepts values between 1 and 2, inclusive.
  43. * # <t>(1,2)</t> -- accepts values between 1 and 2, excluding 1 and 2.
  44. * # <t>{1,2,3,4}</t> -- only values defined in the set are accepted.
  45. * # <t>[-Inf,0)</t> -- accepts value greater or equal to negative infinity
  46. * and strictly less than 0
  47. * Any non-empty combinations of the delimiters of square and round brackets
  48. * are acceptable.
  49. *
  50. * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com>
  51. * @version v1.0, last update on Fri Dec 24 20:46:16 EST 2004
  52. * @package symfony
  53. * @subpackage i18n
  54. */
  55. class sfChoiceFormat
  56. {
  57. /**
  58. * The pattern to validate a set notation
  59. */
  60. protected $validate = '/[\(\[\{]|[-Inf\d]+|,|[\+Inf\d]+|[\)\]\}]/ms';
  61. /**
  62. * The pattern to parse the formatting string.
  63. */
  64. protected $parse = '/\s?\|?([\(\[\{]([-Inf\d]+,?[\+Inf\d]*)+[\)\]\}])\s?/';
  65. /**
  66. * The value for positive infinity.
  67. */
  68. protected $inf;
  69. /**
  70. * Constructor.
  71. */
  72. public function __construct()
  73. {
  74. $this->inf = -log(0);
  75. }
  76. /**
  77. * Determines if the given number belongs to a given set
  78. *
  79. * @param float the number to test.
  80. * @param string the set, in set notation.
  81. * @return boolean true if number is in the set, false otherwise.
  82. */
  83. public function isValid($number, $set)
  84. {
  85. $n = preg_match_all($this->validate, $set, $matches, PREG_SET_ORDER);
  86. if ($n < 3)
  87. {
  88. $error = 'Invalid set "%s"';
  89. $error = sprintf($error, $set);
  90. throw new sfException($error);
  91. }
  92. $leftBracket = $matches[0][0];
  93. $rightBracket = $matches[$n - 1][0];
  94. $i = 0;
  95. $elements = array();
  96. foreach ($matches as $match)
  97. {
  98. $string = $match[0];
  99. if ($i != 0 && $i != $n - 1 && $string !== ',')
  100. {
  101. if ($string == '-Inf')
  102. {
  103. $elements[] = -1 * $this->inf;
  104. }
  105. else if ($string == '+Inf' || $string == 'Inf')
  106. {
  107. $elements[] = $this->inf;
  108. }
  109. else
  110. {
  111. $elements[] = floatval($string);
  112. }
  113. }
  114. $i++;
  115. }
  116. $total = count($elements);
  117. $number = floatval($number);
  118. if ($leftBracket == '{' && $rightBracket == '}')
  119. {
  120. return in_array($number, $elements);
  121. }
  122. $left = false;
  123. if ($leftBracket == '[')
  124. {
  125. $left = $number >= $elements[0];
  126. }
  127. else if ($leftBracket == '(')
  128. {
  129. $left = $number > $elements[0];
  130. }
  131. $right = false;
  132. if ($rightBracket==']')
  133. {
  134. $right = $number <= $elements[$total - 1];
  135. }
  136. else if ($rightBracket == ')')
  137. {
  138. $right = $number < $elements[$total - 1];
  139. }
  140. if ($left && $right)
  141. {
  142. return true;
  143. }
  144. return false;
  145. }
  146. /**
  147. * Parses a choice string and get a list of sets and a list of strings corresponding to the sets.
  148. *
  149. * @param string the string containing the choices
  150. * @return array array($sets, $strings)
  151. */
  152. public function parse($string)
  153. {
  154. $n = preg_match_all($this->parse, $string, $matches, PREG_OFFSET_CAPTURE);
  155. $sets = array();
  156. foreach ($matches[1] as $match)
  157. {
  158. $sets[] = $match[0];
  159. }
  160. $offset = $matches[0];
  161. $strings = array();
  162. for ($i = 0; $i < $n; $i++)
  163. {
  164. $len = strlen($offset[$i][0]);
  165. $begin = $i == 0 ? $len : $offset[$i][1] + $len;
  166. $end = $i == $n - 1 ? strlen($string) : $offset[$i + 1][1];
  167. $strings[] = substr($string, $begin, $end - $begin);
  168. }
  169. return array($sets, $strings);
  170. }
  171. /**
  172. * For the choice string, and a number, find and return the string that satisfied the set within the choices.
  173. *
  174. * @param string the choices string.
  175. * @param float the number to test.
  176. * @return string the choosen string.
  177. */
  178. public function format($string, $number)
  179. {
  180. list($sets, $strings) = $this->parse($string);
  181. $total = count($sets);
  182. for ($i = 0; $i < $total; $i++)
  183. {
  184. if ($this->isValid($number, $sets[$i]))
  185. {
  186. return $strings[$i];
  187. }
  188. }
  189. return false;
  190. }
  191. }