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. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
MetaCharacters.php
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 }