[ Index ]

PHP Cross Reference of phpBB-3.3.14-deutsch

title

Body

[close]

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

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


Generated: Mon Nov 25 19:05:08 2024 Cross-referenced by PHPXref 0.7.1