Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

MetaCharacters.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 4.73 KiB


001  <?php declare(strict_types=1);
002   
003  /**
004  * @package   s9e\RegexpBuilder
005  * @copyright Copyright (c) 2016-2022 The s9e authors
006  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
007  */
008  namespace s9e\RegexpBuilder;
009   
010  use InvalidArgumentException;
011  use function count, preg_match;
012  use s9e\RegexpBuilder\Input\InputInterface;
013   
014  class MetaCharacters
015  {
016      /**
017      * @const Bit value that indicates whether a meta-character represents a single character usable
018      *        in a character class
019      */
020      const IS_CHAR = 1;
021   
022      /**
023      * @const Bit value that indicates whether a meta-character represents a quantifiable expression
024      */
025      const IS_QUANTIFIABLE = 2;
026   
027      /**
028      * @var array Map of meta values and the expression they represent
029      */
030      protected $exprs = [];
031   
032      /**
033      * @var InputInterface
034      */
035      protected $input;
036   
037      /**
038      * @var array Map of meta-characters' codepoints and their value
039      */
040      protected $meta = [];
041   
042      /**
043      * @param InputInterface $input
044      */
045      public function __construct(InputInterface $input)
046      {
047          $this->input = $input;
048      }
049   
050      /**
051      * Add a meta-character to the list
052      *
053      * @param  string $char Meta-character
054      * @param  string $expr Regular expression
055      * @return void
056      */
057      public function add(string $char, string $expr): void
058      {
059          $split = $this->input->split($char);
060          if (count($split) !== 1)
061          {
062              throw new InvalidArgumentException('Meta-characters must be represented by exactly one character');
063          }
064          if (@preg_match('(' . $expr . ')u', '') === false)
065          {
066              throw new InvalidArgumentException("Invalid expression '" . $expr . "'");
067          }
068   
069          $inputValue = $split[0];
070          $metaValue  = $this->computeValue($expr);
071   
072          $this->exprs[$metaValue] = $expr;
073          $this->meta[$inputValue] = $metaValue;
074      }
075   
076      /**
077      * Get the expression associated with a meta value
078      *
079      * @param  integer $metaValue
080      * @return string
081      */
082      public function getExpression(int $metaValue): string
083      {
084          if (!isset($this->exprs[$metaValue]))
085          {
086              throw new InvalidArgumentException('Invalid meta value ' . $metaValue);
087          }
088   
089          return $this->exprs[$metaValue];
090      }
091   
092      /**
093      * Return whether a given value represents a single character usable in a character class
094      *
095      * @param  integer $value
096      * @return bool
097      */
098      public static function isChar(int $value): bool
099      {
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  }