0x1949 Team - FAZEMRX - MANAGER
Edit File: MetaCharacters.php
<?php declare(strict_types=1); /** * @package s9e\RegexpBuilder * @copyright Copyright (c) 2016-2022 The s9e authors * @license http://www.opensource.org/licenses/mit-license.php The MIT License */ namespace s9e\RegexpBuilder; use InvalidArgumentException; use function count, preg_match; use s9e\RegexpBuilder\Input\InputInterface; class MetaCharacters { /** * @const Bit value that indicates whether a meta-character represents a single character usable * in a character class */ const IS_CHAR = 1; /** * @const Bit value that indicates whether a meta-character represents a quantifiable expression */ const IS_QUANTIFIABLE = 2; /** * @var array Map of meta values and the expression they represent */ protected $exprs = []; /** * @var InputInterface */ protected $input; /** * @var array Map of meta-characters' codepoints and their value */ protected $meta = []; /** * @param InputInterface $input */ public function __construct(InputInterface $input) { $this->input = $input; } /** * Add a meta-character to the list * * @param string $char Meta-character * @param string $expr Regular expression * @return void */ public function add(string $char, string $expr): void { $split = $this->input->split($char); if (count($split) !== 1) { throw new InvalidArgumentException('Meta-characters must be represented by exactly one character'); } if (@preg_match('(' . $expr . ')u', '') === false) { throw new InvalidArgumentException("Invalid expression '" . $expr . "'"); } $inputValue = $split[0]; $metaValue = $this->computeValue($expr); $this->exprs[$metaValue] = $expr; $this->meta[$inputValue] = $metaValue; } /** * Get the expression associated with a meta value * * @param integer $metaValue * @return string */ public function getExpression(int $metaValue): string { if (!isset($this->exprs[$metaValue])) { throw new InvalidArgumentException('Invalid meta value ' . $metaValue); } return $this->exprs[$metaValue]; } /** * Return whether a given value represents a single character usable in a character class * * @param integer $value * @return bool */ public static function isChar(int $value): bool { return ($value >= 0 || ($value & self::IS_CHAR)); } /** * Return whether a given value represents a quantifiable expression * * @param integer $value * @return bool */ public static function isQuantifiable(int $value): bool { return ($value >= 0 || ($value & self::IS_QUANTIFIABLE)); } /** * Replace values from meta-characters in a list of strings with their meta value * * @param array[] $strings * @return array[] */ public function replaceMeta(array $strings): array { foreach ($strings as &$string) { foreach ($string as &$value) { if (isset($this->meta[$value])) { $value = $this->meta[$value]; } } } return $strings; } /** * Compute and return a value for given expression * * Values are meant to be a unique negative integer. The least significant bits are used to * store the expression's properties * * @param string $expr Regular expression * @return integer */ protected function computeValue(string $expr): int { $properties = [ self::IS_CHAR => 'exprIsChar', self::IS_QUANTIFIABLE => 'exprIsQuantifiable' ]; $value = (1 + count($this->meta)) * -(2 ** count($properties)); foreach ($properties as $bitValue => $methodName) { if ($this->$methodName($expr)) { $value |= $bitValue; } } return $value; } /** * Test whether given expression represents a single character usable in a character class * * @param string $expr * @return bool */ protected function exprIsChar(string $expr): bool { $regexps = [ // Escaped literal or escape sequence such as \w but not \R '(^\\\\[adefhnrstvwDHNSVW\\W]$)D', // Unicode properties such as \pL or \p{Lu} '(^\\\\p(?:.|\\{[^}]+\\})$)Di', // An escape sequence such as \x1F or \x{2600} '(^\\\\x(?:[0-9a-f]{2}|\\{[^}]+\\})$)Di' ]; return $this->matchesAny($expr, $regexps); } /** * Test whether given expression is quantifiable * * @param string $expr * @return bool */ protected function exprIsQuantifiable(string $expr): bool { $regexps = [ // A dot or \R '(^(?:\\.|\\\\R)$)D', // A character class '(^\\[\\^?(?:([^\\\\\\]]|\\\\.)(?:-(?-1))?)++\\]$)D' ]; return $this->matchesAny($expr, $regexps) || $this->exprIsChar($expr); } /** * Test whether given expression matches any of the given regexps * * @param string $expr * @param string[] $regexps * @return bool */ protected function matchesAny(string $expr, array $regexps): bool { foreach ($regexps as $regexp) { if (preg_match($regexp, $expr)) { return true; } } return false; } }