Interval.php 2.8KB

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