[ Index ]

PHP Cross Reference of phpBB-3.3.3-deutsch

title

Body

[close]

/vendor/s9e/regexp-builder/src/ -> MetaCharacters.php (source)

   1  <?php
   2  
   3  /**
   4  * @package   s9e\RegexpBuilder
   5  * @copyright Copyright (c) 2016-2020 The s9e authors
   6  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
   7  */
   8  namespace s9e\RegexpBuilder;
   9  
  10  use InvalidArgumentException;
  11  use s9e\RegexpBuilder\Input\InputInterface;
  12  
  13  class MetaCharacters
  14  {
  15      /**
  16      * @const Bit value that indicates whether a meta-character represents a single character usable
  17      *        in a character class
  18      */
  19      const IS_CHAR = 1;
  20  
  21      /**
  22      * @const Bit value that indicates whether a meta-character represents a quantifiable expression
  23      */
  24      const IS_QUANTIFIABLE = 2;
  25  
  26      /**
  27      * @var array Map of meta values and the expression they represent
  28      */
  29      protected $exprs = [];
  30  
  31      /**
  32      * @var InputInterface
  33      */
  34      protected $input;
  35  
  36      /**
  37      * @var array Map of meta-characters' codepoints and their value
  38      */
  39      protected $meta = [];
  40  
  41      /**
  42      * @param InputInterface $input
  43      */
  44  	public function __construct(InputInterface $input)
  45      {
  46          $this->input = $input;
  47      }
  48  
  49      /**
  50      * Add a meta-character to the list
  51      *
  52      * @param  string $char Meta-character
  53      * @param  string $expr Regular expression
  54      * @return void
  55      */
  56  	public function add($char, $expr)
  57      {
  58          $split = $this->input->split($char);
  59          if (count($split) !== 1)
  60          {
  61              throw new InvalidArgumentException('Meta-characters must be represented by exactly one character');
  62          }
  63          if (@preg_match('(' . $expr . ')u', '') === false)
  64          {
  65              throw new InvalidArgumentException("Invalid expression '" . $expr . "'");
  66          }
  67  
  68          $inputValue = $split[0];
  69          $metaValue  = $this->computeValue($expr);
  70  
  71          $this->exprs[$metaValue] = $expr;
  72          $this->meta[$inputValue] = $metaValue;
  73      }
  74  
  75      /**
  76      * Get the expression associated with a meta value
  77      *
  78      * @param  integer $metaValue
  79      * @return string
  80      */
  81  	public function getExpression($metaValue)
  82      {
  83          if (!isset($this->exprs[$metaValue]))
  84          {
  85              throw new InvalidArgumentException('Invalid meta value ' . $metaValue);
  86          }
  87  
  88          return $this->exprs[$metaValue];
  89      }
  90  
  91      /**
  92      * Return whether a given value represents a single character usable in a character class
  93      *
  94      * @param  integer $value
  95      * @return bool
  96      */
  97  	public static function isChar($value)
  98      {
  99          return ($value >= 0 || ($value & self::IS_CHAR));
 100      }
 101  
 102      /**
 103      * Return whether a given value represents a quantifiable expression
 104      *
 105      * @param  integer $value
 106      * @return bool
 107      */
 108  	public static function isQuantifiable($value)
 109      {
 110          return ($value >= 0 || ($value & self::IS_QUANTIFIABLE));
 111      }
 112  
 113      /**
 114      * Replace values from meta-characters in a list of strings with their meta value
 115      *
 116      * @param  array[] $strings
 117      * @return array[]
 118      */
 119  	public function replaceMeta(array $strings)
 120      {
 121          foreach ($strings as &$string)
 122          {
 123              foreach ($string as &$value)
 124              {
 125                  if (isset($this->meta[$value]))
 126                  {
 127                      $value = $this->meta[$value];
 128                  }
 129              }
 130          }
 131  
 132          return $strings;
 133      }
 134  
 135      /**
 136      * Compute and return a value for given expression
 137      *
 138      * Values are meant to be a unique negative integer. The last 2 bits indicate whether the
 139      * expression is quantifiable and/or represents a single character.
 140      *
 141      * @param  string  $expr Regular expression
 142      * @return integer
 143      */
 144  	protected function computeValue($expr)
 145      {
 146          $properties = [
 147              'exprIsChar'         => self::IS_CHAR,
 148              'exprIsQuantifiable' => self::IS_QUANTIFIABLE
 149          ];
 150          $value = (1 + count($this->meta)) * -pow(2, count($properties));
 151          foreach ($properties as $methodName => $bitValue)
 152          {
 153              if ($this->$methodName($expr))
 154              {
 155                  $value |= $bitValue;
 156              }
 157          }
 158  
 159          return $value;
 160      }
 161  
 162      /**
 163      * Test whether given expression represents a single character usable in a character class
 164      *
 165      * @param  string $expr
 166      * @return bool
 167      */
 168  	protected function exprIsChar($expr)
 169      {
 170          $regexps = [
 171              // Escaped literal or escape sequence such as \w but not \R
 172              '(^\\\\[adefhnrstvwDHNSVW\\W]$)D',
 173  
 174              // Unicode properties such as \pL or \p{Lu}
 175              '(^\\\\p(?:.|\\{[^}]+\\})$)Di',
 176  
 177              // An escape sequence such as \x1F or \x{2600}
 178              '(^\\\\x(?:[0-9a-f]{2}|\\{[^}]+\\})$)Di'
 179          ];
 180  
 181          return $this->matchesAny($expr, $regexps);
 182      }
 183  
 184      /**
 185      * Test whether given expression is quantifiable
 186      *
 187      * @param  string $expr
 188      * @return bool
 189      */
 190  	protected function exprIsQuantifiable($expr)
 191      {
 192          $regexps = [
 193              // A dot or \R
 194              '(^(?:\\.|\\\\R)$)D',
 195  
 196              // A character class
 197              '(^\\[\\^?(?:([^\\\\\\]]|\\\\.)(?:-(?-1))?)++\\]$)D'
 198          ];
 199  
 200          return $this->matchesAny($expr, $regexps) || $this->exprIsChar($expr);
 201      }
 202  
 203      /**
 204      * Test whether given expression matches any of the given regexps
 205      *
 206      * @param  string   $expr
 207      * @param  string[] $regexps
 208      * @return bool
 209      */
 210  	protected function matchesAny($expr, array $regexps)
 211      {
 212          foreach ($regexps as $regexp)
 213          {
 214              if (preg_match($regexp, $expr))
 215              {
 216                  return true;
 217              }
 218          }
 219  
 220          return false;
 221      }
 222  }


Generated: Sun Feb 14 20:08:31 2021 Cross-referenced by PHPXref 0.7.1