GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — develop ( 588978...0eef41 )
by Baptiste
05:13
created

src/Str.php (1 issue)

1
<?php
2
declare(strict_types = 1);
3
4
namespace Innmind\Immutable;
5
6
use Innmind\Immutable\{
7
    Exception\RegexException,
8
    Exception\SubstringException,
9
    Exception\LogicException
10
};
11
12
final class Str
13
{
14
    private const PAD_RIGHT = STR_PAD_RIGHT;
15
    private const PAD_LEFT = STR_PAD_LEFT;
16
    private const PAD_BOTH = STR_PAD_BOTH;
17
    private const PREG_NO_FLAGS = 0;
18
    private const PREG_SPLIT_NO_EMPTY = PREG_SPLIT_NO_EMPTY;
19
    private const PREG_SPLIT_DELIM_CAPTURE = PREG_SPLIT_DELIM_CAPTURE;
20
    private const PREG_SPLIT_OFFSET_CAPTURE = PREG_SPLIT_OFFSET_CAPTURE;
21
    private const PREG_OFFSET_CAPTURE = PREG_OFFSET_CAPTURE;
22
23
    private string $value;
24
    private ?string $encoding;
25
26 251
    public function __construct(string $value, string $encoding = null)
27
    {
28 251
        $this->value = $value;
29 251
        $this->encoding = $encoding;
30 251
    }
31
32 215
    public static function of(string $value, string $encoding = null): self
33
    {
34 215
        return new self($value, $encoding);
35
    }
36
37
    /**
38
     * {@inheritdoc}
39
     */
40 249
    public function __toString(): string
41
    {
42 249
        return $this->value;
43
    }
44
45 228
    public function encoding(): self
46
    {
47 228
        if (\is_null($this->encoding)) {
48 224
            $this->encoding = \mb_internal_encoding();
49
        }
50
51 228
        return new self($this->encoding);
52
    }
53
54 15
    public function toEncoding(string $encoding): self
55
    {
56 15
        return new self($this->value, $encoding);
57
    }
58
59
    /**
60
     * Split the string into a collection of ones
61
     *
62
     * @return Stream<self>
63
     */
64 8
    public function split(string $delimiter = null): Stream
65
    {
66 8
        if (\is_null($delimiter) || $delimiter === '') {
67 3
            return $this->chunk();
68
        }
69
70 6
        $parts = \explode($delimiter, $this->value);
71 6
        $stream = new Stream(self::class);
72
73 6
        foreach ($parts as $part) {
74 6
            $stream = $stream->add(new self($part, $this->encoding));
75
        }
76
77 6
        return $stream;
78
    }
79
80
    /**
81
     * Returns a collection of the string splitted by the given chunk size
82
     *
83
     * @return Stream<self>
84
     */
85 7
    public function chunk(int $size = 1): Stream
86
    {
87 7
        $stream = new Stream(self::class);
88 7
        $string = $this;
0 ignored issues
show
The assignment to $string is dead and can be removed.
Loading history...
89 7
        $parts = \mb_str_split($this->value, $size, (string) $this->encoding());
90
91 7
        foreach ($parts as $value) {
92 7
            $stream = $stream->add(new self($value, $this->encoding));
93
        }
94
95 7
        return $stream;
96
    }
97
98
    /**
99
     * Returns the position of the first occurence of the string
100
     *
101
     * @throws SubstringException If the string is not found
102
     */
103 211
    public function position(string $needle, int $offset = 0): int
104
    {
105 211
        $position = \mb_strpos($this->value, $needle, $offset, (string) $this->encoding());
106
107 211
        if ($position === false) {
108 209
            throw new SubstringException(\sprintf(
109 209
                'Substring "%s" not found',
110 209
                $needle
111
            ));
112
        }
113
114 7
        return (int) $position;
115
    }
116
117
    /**
118
     * Replace all occurences of the search string with the replacement one
119
     */
120 2
    public function replace(string $search, string $replacement): self
121
    {
122 2
        if (!$this->contains($search)) {
123 1
            return $this;
124
        }
125
126
        return $this
127 2
            ->split($search)
128 2
            ->join($replacement);
129
    }
130
131
    /**
132
     * Returns the string following the given delimiter
133
     *
134
     * @throws SubstringException If the string is not found
135
     */
136 3
    public function str(string $delimiter): self
137
    {
138 3
        $sub = \mb_strstr($this->value, $delimiter, false, (string) $this->encoding());
139
140 3
        if ($sub === false) {
141 1
            throw new SubstringException(\sprintf(
142 1
                'Substring "%s" not found',
143 1
                $delimiter
144
            ));
145
        }
146
147 2
        return new self($sub, $this->encoding);
148
    }
149
150
    /**
151
     * Return the string in upper case
152
     */
153 3
    public function toUpper(): self
154
    {
155 3
        return new self(\mb_strtoupper($this->value), $this->encoding);
156
    }
157
158
    /**
159
     * Return the string in lower case
160
     */
161 2
    public function toLower(): self
162
    {
163 2
        return new self(\mb_strtolower($this->value), $this->encoding);
164
    }
165
166
    /**
167
     * Return the string length
168
     */
169 15
    public function length(): int
170
    {
171 15
        return \mb_strlen($this->value, (string) $this->encoding());
172
    }
173
174 1
    public function empty(): bool
175
    {
176 1
        return $this->value === '';
177
    }
178
179
    /**
180
     * Reverse the string
181
     */
182 1
    public function reverse(): self
183
    {
184
        return $this
185 1
            ->chunk()
186 1
            ->reverse()
187 1
            ->join('');
188
    }
189
190
    /**
191
     * Pad to the right
192
     */
193 1
    public function rightPad(int $length, string $character = ' '): self
194
    {
195 1
        return $this->pad($length, $character, self::PAD_RIGHT);
196
    }
197
198
    /**
199
     * Pad to the left
200
     */
201 1
    public function leftPad(int $length, string $character = ' '): self
202
    {
203 1
        return $this->pad($length, $character, self::PAD_LEFT);
204
    }
205
206
    /**
207
     * Pad both sides
208
     */
209 1
    public function uniPad(int $length, string $character = ' '): self
210
    {
211 1
        return $this->pad($length, $character, self::PAD_BOTH);
212
    }
213
214
    /**
215
     * Find length of initial segment not matching mask
216
     */
217 1
    public function cspn(string $mask, int $start = 0, int $length = null): int
218
    {
219 1
        if ($length === null) {
220 1
            $value = \strcspn($this->value, $mask, $start);
221
        } else {
222 1
            $value = \strcspn(
223 1
                $this->value,
224 1
                $mask,
225 1
                $start,
226 1
                $length
227
            );
228
        }
229
230 1
        return (int) $value;
231
    }
232
233
    /**
234
     * Repeat the string n times
235
     */
236 1
    public function repeat(int $repeat): self
237
    {
238 1
        return new self(\str_repeat($this->value, $repeat), $this->encoding);
239
    }
240
241
    /**
242
     * Shuffle the string
243
     */
244 2
    public function shuffle(): self
245
    {
246 2
        $parts = $this->chunk()->toArray();
247 2
        \shuffle($parts);
248
249 2
        return new self(\implode('', $parts), $this->encoding);
250
    }
251
252 1
    public function stripSlashes(): self
253
    {
254 1
        return new self(\stripslashes($this->value), $this->encoding);
255
    }
256
257
    /**
258
     * Strip C-like slashes
259
     */
260 1
    public function stripCSlashes(): self
261
    {
262 1
        return new self(\stripcslashes($this->value), $this->encoding);
263
    }
264
265
    /**
266
     * Return the word count
267
     */
268 1
    public function wordCount(string $charlist = ''): int
269
    {
270 1
        return (int) \str_word_count(
271 1
            $this->value,
272 1
            0,
273 1
            $charlist
274
        );
275
    }
276
277
    /**
278
     * Return the collection of words
279
     *
280
     * @return Map<int, self>
281
     */
282 1
    public function words(string $charlist = ''): Map
283
    {
284 1
        $words = \str_word_count($this->value, 2, $charlist);
285 1
        $map = new Map('int', self::class);
286
287 1
        foreach ($words as $position => $word) {
288 1
            $map = $map->put($position, new self($word, $this->encoding));
289
        }
290
291 1
        return $map;
292
    }
293
294
    /**
295
     * Split the string using a regular expression
296
     *
297
     * @return Stream<self>
298
     */
299 2
    public function pregSplit(string $regex, int $limit = -1): Stream
300
    {
301 2
        $strings = \preg_split($regex, $this->value, $limit);
302 2
        $stream = new Stream(self::class);
303
304 2
        foreach ($strings as $string) {
305 2
            $stream = $stream->add(new self($string, $this->encoding));
306
        }
307
308 2
        return $stream;
309
    }
310
311
    /**
312
     * Check if the string match the given regular expression
313
     *
314
     * @throws Exception If the regex failed
315
     */
316 2
    public function matches(string $regex): bool
317
    {
318 2
        if (\func_num_args() !== 1) {
319
            throw new LogicException('Offset is no longer supported');
320
        }
321
322 2
        return RegExp::of($regex)->matches($this);
323
    }
324
325
    /**
326
     * Return a collection of the elements matching the regex
327
     *
328
     * @throws Exception If the regex failed
329
     *
330
     * @return Map<scalar, self>
331
     */
332 3
    public function capture(string $regex): Map
333
    {
334 3
        return RegExp::of($regex)->capture($this);
335
    }
336
337
    /**
338
     * Replace part of the string by using a regular expression
339
     *
340
     * @throws Exception If the regex failed
341
     */
342 1
    public function pregReplace(
343
        string $regex,
344
        string $replacement,
345
        int $limit = -1
346
    ): self {
347 1
        $value = \preg_replace(
348 1
            $regex,
349 1
            $replacement,
350 1
            $this->value,
351 1
            $limit
352
        );
353
354 1
        if ($value === null) {
355
            throw new RegexException('', \preg_last_error());
356
        }
357
358 1
        return new self($value, $this->encoding);
359
    }
360
361
    /**
362
     * Return part of the string
363
     */
364 12
    public function substring(int $start, int $length = null): self
365
    {
366 12
        if ($this->length() === 0) {
367 1
            return $this;
368
        }
369
370 12
        $sub = \mb_substr($this->value, $start, $length, (string) $this->encoding());
371
372 12
        return new self($sub, $this->encoding);
373
    }
374
375 1
    public function take(int $size): self
376
    {
377 1
        return $this->substring(0, $size);
378
    }
379
380 2
    public function takeEnd(int $size): self
381
    {
382 2
        return $this->substring(-$size);
383
    }
384
385 2
    public function drop(int $size): self
386
    {
387 2
        return $this->substring($size);
388
    }
389
390 1
    public function dropEnd(int $size): self
391
    {
392 1
        return $this->substring(0, $this->length() - $size);
393
    }
394
395
    /**
396
     * Return a formatted string
397
     */
398 1
    public function sprintf(...$values): self
399
    {
400 1
        return new self(\sprintf($this->value, ...$values), $this->encoding);
401
    }
402
403
    /**
404
     * Return the string with the first letter as uppercase
405
     */
406 2
    public function ucfirst(): self
407
    {
408
        return $this
409 2
            ->substring(0, 1)
410 2
            ->toUpper()
411 2
            ->append((string) $this->substring(1));
412
    }
413
414
    /**
415
     * Return the string with the first letter as lowercase
416
     */
417 1
    public function lcfirst(): self
418
    {
419
        return $this
420 1
            ->substring(0, 1)
421 1
            ->toLower()
422 1
            ->append((string) $this->substring(1));
423
    }
424
425
    /**
426
     * Return a CamelCase representation of the string
427
     */
428 1
    public function camelize(): self
429
    {
430
        return $this
431 1
            ->pregSplit('/_| /')
432
            ->map(function(self $part) {
433 1
                return $part->ucfirst();
434 1
            })
435 1
            ->join('')
436 1
            ->toEncoding((string) $this->encoding());
437
    }
438
439
    /**
440
     * Append a string at the end of the current one
441
     */
442 4
    public function append(string $string): self
443
    {
444 4
        return new self((string) $this.$string, $this->encoding);
445
    }
446
447
    /**
448
     * Prepend a string at the beginning of the current one
449
     */
450 1
    public function prepend(string $string): self
451
    {
452 1
        return new self($string.(string) $this, $this->encoding);
453
    }
454
455
    /**
456
     * Check if the 2 strings are equal
457
     */
458 1
    public function equals(self $string): bool
459
    {
460 1
        return (string) $this === (string) $string;
461
    }
462
463
    /**
464
     * Trim the string
465
     */
466 1
    public function trim(string $mask = null): self
467
    {
468 1
        return new self(
469 1
            $mask === null ? \trim((string) $this) : \trim((string) $this, $mask),
470 1
            $this->encoding
471
        );
472
    }
473
474
    /**
475
     * Trim the right side of the string
476
     */
477 1
    public function rightTrim(string $mask = null): self
478
    {
479 1
        return new self(
480 1
            $mask === null ? \rtrim((string) $this) : \rtrim((string) $this, $mask),
481 1
            $this->encoding
482
        );
483
    }
484
485
    /**
486
     * Trim the left side of the string
487
     */
488 1
    public function leftTrim(string $mask = null): self
489
    {
490 1
        return new self(
491 1
            $mask === null ? \ltrim((string) $this) : \ltrim((string) $this, $mask),
492 1
            $this->encoding
493
        );
494
    }
495
496
    /**
497
     * Check if the given string is present in the current one
498
     */
499 208
    public function contains(string $value): bool
500
    {
501
        try {
502 208
            $this->position($value);
503
504 5
            return true;
505 207
        } catch (SubstringException $e) {
506 207
            return false;
507
        }
508
    }
509
510
    /**
511
     * Check if the current string starts with the given string
512
     */
513 207
    public function startsWith(string $value): bool
514
    {
515 207
        if ($value === '') {
516 1
            return true;
517
        }
518
519
        try {
520 207
            return $this->position($value) === 0;
521 207
        } catch (SubstringException $e) {
522 207
            return false;
523
        }
524
    }
525
526
    /**
527
     * Check if the current string ends with the given string
528
     */
529 1
    public function endsWith(string $value): bool
530
    {
531 1
        if ($value === '') {
532 1
            return true;
533
        }
534
535 1
        return (string) $this->takeEnd(self::of($value, $this->encoding)->length()) === $value;
536
    }
537
538
    /**
539
     * Quote regular expression characters
540
     */
541 1
    public function pregQuote(string $delimiter = ''): self
542
    {
543 1
        return new self(\preg_quote((string) $this, $delimiter), $this->encoding);
544
    }
545
546
    /**
547
     * Pad the string
548
     */
549 1
    private function pad(
550
        int $length,
551
        string $character = ' ',
552
        int $direction = self::PAD_RIGHT
553
    ): self {
554 1
        return new self(\str_pad(
555 1
            $this->value,
556 1
            $length,
557 1
            $character,
558 1
            $direction
559 1
        ), $this->encoding);
560
    }
561
}
562