Interval.php 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Translation;
  11. /**
  12. * Tests if a given number belongs to a given math interval.
  13. *
  14. * An interval can represent a finite set of numbers:
  15. *
  16. * {1,2,3,4}
  17. *
  18. * An interval can represent numbers between two numbers:
  19. *
  20. * [1, +Inf]
  21. * ]-1,2[
  22. *
  23. * The left delimiter can be [ (inclusive) or ] (exclusive).
  24. * The right delimiter can be [ (exclusive) or ] (inclusive).
  25. * Beside numbers, you can use -Inf and +Inf for the infinite.
  26. *
  27. * @author Fabien Potencier <fabien@symfony.com>
  28. *
  29. * @see http://en.wikipedia.org/wiki/Interval_%28mathematics%29#The_ISO_notation
  30. */
  31. class Interval
  32. {
  33. /**
  34. * Tests if the given number is in the math interval.
  35. *
  36. * @param int $number A number
  37. * @param string $interval An interval
  38. *
  39. * @return bool
  40. *
  41. * @throws \InvalidArgumentException
  42. */
  43. public static function test($number, $interval)
  44. {
  45. $interval = trim($interval);
  46. if (!preg_match('/^'.self::getIntervalRegexp().'$/x', $interval, $matches)) {
  47. throw new \InvalidArgumentException(sprintf('"%s" is not a valid interval.', $interval));
  48. }
  49. if ($matches[1]) {
  50. foreach (explode(',', $matches[2]) as $n) {
  51. if ($number == $n) {
  52. return true;
  53. }
  54. }
  55. } else {
  56. $leftNumber = self::convertNumber($matches['left']);
  57. $rightNumber = self::convertNumber($matches['right']);
  58. return
  59. ('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber)
  60. && (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber)
  61. ;
  62. }
  63. return false;
  64. }
  65. /**
  66. * Returns a Regexp that matches valid intervals.
  67. *
  68. * @return string A Regexp (without the delimiters)
  69. */
  70. public static function getIntervalRegexp()
  71. {
  72. return <<<EOF
  73. ({\s*
  74. (\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*)
  75. \s*})
  76. |
  77. (?P<left_delimiter>[\[\]])
  78. \s*
  79. (?P<left>-Inf|\-?\d+(\.\d+)?)
  80. \s*,\s*
  81. (?P<right>\+?Inf|\-?\d+(\.\d+)?)
  82. \s*
  83. (?P<right_delimiter>[\[\]])
  84. EOF;
  85. }
  86. private static function convertNumber($number)
  87. {
  88. if ('-Inf' === $number) {
  89. return log(0);
  90. } elseif ('+Inf' === $number || 'Inf' === $number) {
  91. return -log(0);
  92. }
  93. return (float) $number;
  94. }
  95. }