PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.8.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.8.2
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / vendor / prefixed / symfony / string / UnicodeString.php
matomo / app / vendor / prefixed / symfony / string Last commit date
Exception 2 years ago Inflector 1 year ago Resources 1 year ago Slugger 1 year ago AbstractString.php 1 year ago AbstractUnicodeString.php 1 year ago ByteString.php 1 year ago CodePointString.php 1 year ago LICENSE 2 years ago LazyString.php 2 years ago README.md 2 years ago UnicodeString.php 1 year ago
UnicodeString.php
303 lines
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 namespace Matomo\Dependencies\Symfony\Component\String;
12
13 use Matomo\Dependencies\Symfony\Component\String\Exception\ExceptionInterface;
14 use Matomo\Dependencies\Symfony\Component\String\Exception\InvalidArgumentException;
15 /**
16 * Represents a string of Unicode grapheme clusters encoded as UTF-8.
17 *
18 * A letter followed by combining characters (accents typically) form what Unicode defines
19 * as a grapheme cluster: a character as humans mean it in written texts. This class knows
20 * about the concept and won't split a letter apart from its combining accents. It also
21 * ensures all string comparisons happen on their canonically-composed representation,
22 * ignoring e.g. the order in which accents are listed when a letter has many of them.
23 *
24 * @see https://unicode.org/reports/tr15/
25 *
26 * @author Nicolas Grekas <p@tchwork.com>
27 * @author Hugo Hamon <hugohamon@neuf.fr>
28 *
29 * @throws ExceptionInterface
30 */
31 class UnicodeString extends AbstractUnicodeString
32 {
33 public function __construct(string $string = '')
34 {
35 $this->string = normalizer_is_normalized($string) ? $string : normalizer_normalize($string);
36 if (\false === $this->string) {
37 throw new InvalidArgumentException('Invalid UTF-8 string.');
38 }
39 }
40 public function append(string ...$suffix) : AbstractString
41 {
42 $str = clone $this;
43 $str->string = $this->string . (1 >= \count($suffix) ? $suffix[0] ?? '' : implode('', $suffix));
44 normalizer_is_normalized($str->string) ?: ($str->string = normalizer_normalize($str->string));
45 if (\false === $str->string) {
46 throw new InvalidArgumentException('Invalid UTF-8 string.');
47 }
48 return $str;
49 }
50 public function chunk(int $length = 1) : array
51 {
52 if (1 > $length) {
53 throw new InvalidArgumentException('The chunk length must be greater than zero.');
54 }
55 if ('' === $this->string) {
56 return [];
57 }
58 $rx = '/(';
59 while (65535 < $length) {
60 $rx .= '\\X{65535}';
61 $length -= 65535;
62 }
63 $rx .= '\\X{' . $length . '})/u';
64 $str = clone $this;
65 $chunks = [];
66 foreach (preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) {
67 $str->string = $chunk;
68 $chunks[] = clone $str;
69 }
70 return $chunks;
71 }
72 public function endsWith($suffix) : bool
73 {
74 if ($suffix instanceof AbstractString) {
75 $suffix = $suffix->string;
76 } elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
77 return parent::endsWith($suffix);
78 } else {
79 $suffix = (string) $suffix;
80 }
81 $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
82 normalizer_is_normalized($suffix, $form) ?: ($suffix = normalizer_normalize($suffix, $form));
83 if ('' === $suffix || \false === $suffix) {
84 return \false;
85 }
86 if ($this->ignoreCase) {
87 return 0 === mb_stripos(grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)), $suffix, 0, 'UTF-8');
88 }
89 return $suffix === grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix));
90 }
91 public function equalsTo($string) : bool
92 {
93 if ($string instanceof AbstractString) {
94 $string = $string->string;
95 } elseif (\is_array($string) || $string instanceof \Traversable) {
96 return parent::equalsTo($string);
97 } else {
98 $string = (string) $string;
99 }
100 $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
101 normalizer_is_normalized($string, $form) ?: ($string = normalizer_normalize($string, $form));
102 if ('' !== $string && \false !== $string && $this->ignoreCase) {
103 return \strlen($string) === \strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8');
104 }
105 return $string === $this->string;
106 }
107 public function indexOf($needle, int $offset = 0) : ?int
108 {
109 if ($needle instanceof AbstractString) {
110 $needle = $needle->string;
111 } elseif (\is_array($needle) || $needle instanceof \Traversable) {
112 return parent::indexOf($needle, $offset);
113 } else {
114 $needle = (string) $needle;
115 }
116 $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
117 normalizer_is_normalized($needle, $form) ?: ($needle = normalizer_normalize($needle, $form));
118 if ('' === $needle || \false === $needle) {
119 return null;
120 }
121 try {
122 $i = $this->ignoreCase ? grapheme_stripos($this->string, $needle, $offset) : grapheme_strpos($this->string, $needle, $offset);
123 } catch (\ValueError $e) {
124 return null;
125 }
126 return \false === $i ? null : $i;
127 }
128 public function indexOfLast($needle, int $offset = 0) : ?int
129 {
130 if ($needle instanceof AbstractString) {
131 $needle = $needle->string;
132 } elseif (\is_array($needle) || $needle instanceof \Traversable) {
133 return parent::indexOfLast($needle, $offset);
134 } else {
135 $needle = (string) $needle;
136 }
137 $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
138 normalizer_is_normalized($needle, $form) ?: ($needle = normalizer_normalize($needle, $form));
139 if ('' === $needle || \false === $needle) {
140 return null;
141 }
142 $string = $this->string;
143 if (0 > $offset) {
144 // workaround https://bugs.php.net/74264
145 if (0 > ($offset += grapheme_strlen($needle))) {
146 $string = grapheme_substr($string, 0, $offset);
147 }
148 $offset = 0;
149 }
150 $i = $this->ignoreCase ? grapheme_strripos($string, $needle, $offset) : grapheme_strrpos($string, $needle, $offset);
151 return \false === $i ? null : $i;
152 }
153 public function join(array $strings, ?string $lastGlue = null) : AbstractString
154 {
155 $str = parent::join($strings, $lastGlue);
156 normalizer_is_normalized($str->string) ?: ($str->string = normalizer_normalize($str->string));
157 return $str;
158 }
159 public function length() : int
160 {
161 return grapheme_strlen($this->string);
162 }
163 /**
164 * @return static
165 */
166 public function normalize(int $form = self::NFC) : parent
167 {
168 $str = clone $this;
169 if (\in_array($form, [self::NFC, self::NFKC], \true)) {
170 normalizer_is_normalized($str->string, $form) ?: ($str->string = normalizer_normalize($str->string, $form));
171 } elseif (!\in_array($form, [self::NFD, self::NFKD], \true)) {
172 throw new InvalidArgumentException('Unsupported normalization form.');
173 } elseif (!normalizer_is_normalized($str->string, $form)) {
174 $str->string = normalizer_normalize($str->string, $form);
175 $str->ignoreCase = null;
176 }
177 return $str;
178 }
179 public function prepend(string ...$prefix) : AbstractString
180 {
181 $str = clone $this;
182 $str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : implode('', $prefix)) . $this->string;
183 normalizer_is_normalized($str->string) ?: ($str->string = normalizer_normalize($str->string));
184 if (\false === $str->string) {
185 throw new InvalidArgumentException('Invalid UTF-8 string.');
186 }
187 return $str;
188 }
189 public function replace(string $from, string $to) : AbstractString
190 {
191 $str = clone $this;
192 normalizer_is_normalized($from) ?: ($from = normalizer_normalize($from));
193 if ('' !== $from && \false !== $from) {
194 $tail = $str->string;
195 $result = '';
196 $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos';
197 while ('' !== $tail && \false !== ($i = $indexOf($tail, $from))) {
198 $slice = grapheme_substr($tail, 0, $i);
199 $result .= $slice . $to;
200 $tail = substr($tail, \strlen($slice) + \strlen($from));
201 }
202 $str->string = $result . $tail;
203 normalizer_is_normalized($str->string) ?: ($str->string = normalizer_normalize($str->string));
204 if (\false === $str->string) {
205 throw new InvalidArgumentException('Invalid UTF-8 string.');
206 }
207 }
208 return $str;
209 }
210 public function replaceMatches(string $fromRegexp, $to) : AbstractString
211 {
212 $str = parent::replaceMatches($fromRegexp, $to);
213 normalizer_is_normalized($str->string) ?: ($str->string = normalizer_normalize($str->string));
214 return $str;
215 }
216 public function slice(int $start = 0, ?int $length = null) : AbstractString
217 {
218 $str = clone $this;
219 if (\PHP_VERSION_ID < 80000 && 0 > $start && grapheme_strlen($this->string) < -$start) {
220 $start = 0;
221 }
222 $str->string = (string) grapheme_substr($this->string, $start, $length ?? 2147483647);
223 return $str;
224 }
225 public function splice(string $replacement, int $start = 0, ?int $length = null) : AbstractString
226 {
227 $str = clone $this;
228 if (\PHP_VERSION_ID < 80000 && 0 > $start && grapheme_strlen($this->string) < -$start) {
229 $start = 0;
230 }
231 $start = $start ? \strlen(grapheme_substr($this->string, 0, $start)) : 0;
232 $length = $length ? \strlen(grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length;
233 $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647);
234 normalizer_is_normalized($str->string) ?: ($str->string = normalizer_normalize($str->string));
235 if (\false === $str->string) {
236 throw new InvalidArgumentException('Invalid UTF-8 string.');
237 }
238 return $str;
239 }
240 public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array
241 {
242 if (1 > ($limit = $limit ?? 2147483647)) {
243 throw new InvalidArgumentException('Split limit must be a positive integer.');
244 }
245 if ('' === $delimiter) {
246 throw new InvalidArgumentException('Split delimiter is empty.');
247 }
248 if (null !== $flags) {
249 return parent::split($delimiter . 'u', $limit, $flags);
250 }
251 normalizer_is_normalized($delimiter) ?: ($delimiter = normalizer_normalize($delimiter));
252 if (\false === $delimiter) {
253 throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.');
254 }
255 $str = clone $this;
256 $tail = $this->string;
257 $chunks = [];
258 $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos';
259 while (1 < $limit && \false !== ($i = $indexOf($tail, $delimiter))) {
260 $str->string = grapheme_substr($tail, 0, $i);
261 $chunks[] = clone $str;
262 $tail = substr($tail, \strlen($str->string) + \strlen($delimiter));
263 --$limit;
264 }
265 $str->string = $tail;
266 $chunks[] = clone $str;
267 return $chunks;
268 }
269 public function startsWith($prefix) : bool
270 {
271 if ($prefix instanceof AbstractString) {
272 $prefix = $prefix->string;
273 } elseif (\is_array($prefix) || $prefix instanceof \Traversable) {
274 return parent::startsWith($prefix);
275 } else {
276 $prefix = (string) $prefix;
277 }
278 $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
279 normalizer_is_normalized($prefix, $form) ?: ($prefix = normalizer_normalize($prefix, $form));
280 if ('' === $prefix || \false === $prefix) {
281 return \false;
282 }
283 if ($this->ignoreCase) {
284 return 0 === mb_stripos(grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES), $prefix, 0, 'UTF-8');
285 }
286 return $prefix === grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES);
287 }
288 public function __wakeup()
289 {
290 if (!\is_string($this->string)) {
291 throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
292 }
293 normalizer_is_normalized($this->string) ?: ($this->string = normalizer_normalize($this->string));
294 }
295 public function __clone()
296 {
297 if (null === $this->ignoreCase) {
298 normalizer_is_normalized($this->string) ?: ($this->string = normalizer_normalize($this->string));
299 }
300 $this->ignoreCase = \false;
301 }
302 }
303