Completed
Push — master ( 522f83...fec5f5 )
by Lars
03:37
created

Stringy::slugify()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 34

Duplication

Lines 6
Ratio 17.65 %

Code Coverage

Tests 20
CRAP Score 5.0026

Importance

Changes 0
Metric Value
cc 5
nc 16
nop 2
dl 6
loc 34
ccs 20
cts 21
cp 0.9524
crap 5.0026
rs 9.0648
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stringy;
6
7
use voku\helper\AntiXSS;
8
use voku\helper\EmailCheck;
9
use voku\helper\URLify;
10
use voku\helper\UTF8;
11
12
/**
13
 * Class Stringy
14
 */
15
class Stringy implements \Countable, \IteratorAggregate, \ArrayAccess
16
{
17
    /**
18
     * An instance's string.
19
     *
20
     * @var string
21
     */
22
    protected $str;
23
24
    /**
25
     * The string's encoding, which should be one of the mbstring module's
26
     * supported encodings.
27
     *
28
     * @var string
29
     */
30
    protected $encoding;
31
32
    /**
33
     * @var UTF8
34
     */
35
    private $utf8;
36
37
    /**
38
     * Initializes a Stringy object and assigns both str and encoding properties
39
     * the supplied values. $str is cast to a string prior to assignment, and if
40
     * $encoding is not specified, it defaults to mb_internal_encoding(). Throws
41
     * an InvalidArgumentException if the first argument is an array or object
42
     * without a __toString method.
43
     *
44
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
45
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
46
     *
47
     * @throws \InvalidArgumentException
48
     *                                   <p>if an array or object without a
49
     *                                   __toString method is passed as the first argument</p>
50
     */
51 2105
    public function __construct($str = '', string $encoding = null)
52
    {
53 2105
        if (\is_array($str)) {
54 2
            throw new \InvalidArgumentException(
55 2
                'Passed value cannot be an array'
56
            );
57
        }
58
59
        if (
60 2103
            \is_object($str)
61
            &&
62 2103
            !\method_exists($str, '__toString')
63
        ) {
64 2
            throw new \InvalidArgumentException(
65 2
                'Passed object must have a __toString method'
66
            );
67
        }
68
69 2101
        $this->str = (string) $str;
70
71 2101
        static $UTF8 = null;
72 2101
        if ($UTF8 === null) {
73
            $UTF8 = new UTF8();
74
        }
75 2101
        $this->utf8 = $UTF8;
76
77 2101
        if ($encoding !== 'UTF-8') {
78 1350
            $this->encoding = $this->utf8::normalize_encoding($encoding, 'UTF-8');
79
        } else {
80 1645
            $this->encoding = $encoding;
81
        }
82 2101
    }
83
84
    /**
85
     * Returns the value in $str.
86
     *
87
     * @return string
88
     *                <p>The current value of the $str property.</p>
89
     */
90 978
    public function __toString()
91
    {
92 978
        return (string) $this->str;
93
    }
94
95
    /**
96
     * Gets the substring after the first occurrence of a separator.
97
     * If no match is found returns new empty Stringy object.
98
     *
99
     * @param string $separator
100
     *
101
     * @return static
102
     */
103 2
    public function afterFirst(string $separator): self
104
    {
105 2
        return static::create(
106 2
            $this->utf8::str_substr_after_first_separator(
107 2
                $this->str,
108 2
                $separator,
109 2
                $this->encoding
110
            )
111
        );
112
    }
113
114
    /**
115
     * Gets the substring after the first occurrence of a separator.
116
     * If no match is found returns new empty Stringy object.
117
     *
118
     * @param string $separator
119
     *
120
     * @return static
121
     */
122 1
    public function afterFirstIgnoreCase(string $separator): self
123
    {
124 1
        return static::create(
125 1
            $this->utf8::str_isubstr_after_first_separator(
126 1
                $this->str,
127 1
                $separator,
128 1
                $this->encoding
129
            )
130
        );
131
    }
132
133
    /**
134
     * Gets the substring after the last occurrence of a separator.
135
     * If no match is found returns new empty Stringy object.
136
     *
137
     * @param string $separator
138
     *
139
     * @return static
140
     */
141 1
    public function afterLast(string $separator): self
142
    {
143 1
        return static::create(
144 1
            $this->utf8::str_substr_after_last_separator(
145 1
                $this->str,
146 1
                $separator,
147 1
                $this->encoding
148
            )
149
        );
150
    }
151
152
    /**
153
     * Gets the substring after the last occurrence of a separator.
154
     * If no match is found returns new empty Stringy object.
155
     *
156
     * @param string $separator
157
     *
158
     * @return static
159
     */
160 1
    public function afterLastIgnoreCase(string $separator): self
161
    {
162 1
        return static::create(
163 1
            $this->utf8::str_isubstr_after_last_separator(
164 1
                $this->str,
165 1
                $separator,
166 1
                $this->encoding
167
            )
168
        );
169
    }
170
171
    /**
172
     * Returns a new string with $string appended.
173
     *
174
     * @param string $string <p>The string to append.</p>
175
     *
176
     * @return static
177
     *                <p>Object with appended $string.</p>
178
     */
179 7
    public function append(string $string): self
180
    {
181 7
        return static::create($this->str . $string, $this->encoding);
182
    }
183
184
    /**
185
     * Append an password (limited to chars that are good readable).
186
     *
187
     * @param int $length <p>Length of the random string.</p>
188
     *
189
     * @return static
190
     *                <p>Object with appended password.</p>
191
     */
192 1
    public function appendPassword(int $length): self
193
    {
194 1
        return $this->appendRandomString(
195 1
            $length,
196 1
            '2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ!?_#'
197
        );
198
    }
199
200
    /**
201
     * Append an random string.
202
     *
203
     * @param int    $length        <p>Length of the random string.</p>
204
     * @param string $possibleChars [optional] <p>Characters string for the random selection.</p>
205
     *
206
     * @return static
207
     *                <p>Object with appended random string.</p>
208
     */
209 2
    public function appendRandomString(int $length, string $possibleChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'): self
210
    {
211 2
        $str = $this->utf8::get_random_string($length, $possibleChars);
212
213 2
        return $this->append($str);
214
    }
215
216
    /**
217
     * Append an unique identifier.
218
     *
219
     * @param int|string $entropyExtra [optional] <p>Extra entropy via a string or int value.</p>
220
     * @param bool       $md5          [optional] <p>Return the unique identifier as md5-hash? Default: true</p>
221
     *
222
     * @return static
223
     *                <p>Object with appended unique identifier as md5-hash.</p>
224
     */
225 1
    public function appendUniqueIdentifier($entropyExtra = '', bool $md5 = true): self
226
    {
227 1
        return $this->append(
228 1
            $this->utf8::get_unique_string($entropyExtra, $md5)
229
        );
230
    }
231
232
    /**
233
     * Returns the character at $index, with indexes starting at 0.
234
     *
235
     * @param int $index <p>Position of the character.</p>
236
     *
237
     * @return static
238
     *                <p>The character at $index.</p>
239
     */
240 16
    public function at(int $index): self
241
    {
242 16
        return static::create($this->utf8::char_at($this->str, $index), $this->encoding);
243
    }
244
245
    /**
246
     * Gets the substring before the first occurrence of a separator.
247
     * If no match is found returns new empty Stringy object.
248
     *
249
     * @param string $separator
250
     *
251
     * @return static
252
     */
253 1
    public function beforeFirst(string $separator): self
254
    {
255 1
        return static::create(
256 1
            $this->utf8::str_substr_before_first_separator(
257 1
                $this->str,
258 1
                $separator,
259 1
                $this->encoding
260
            )
261
        );
262
    }
263
264
    /**
265
     * Gets the substring before the first occurrence of a separator.
266
     * If no match is found returns new empty Stringy object.
267
     *
268
     * @param string $separator
269
     *
270
     * @return static
271
     */
272 1
    public function beforeFirstIgnoreCase(string $separator): self
273
    {
274 1
        return static::create(
275 1
            $this->utf8::str_isubstr_before_first_separator(
276 1
                $this->str,
277 1
                $separator,
278 1
                $this->encoding
279
            )
280
        );
281
    }
282
283
    /**
284
     * Gets the substring before the last occurrence of a separator.
285
     * If no match is found returns new empty Stringy object.
286
     *
287
     * @param string $separator
288
     *
289
     * @return static
290
     */
291 1
    public function beforeLast(string $separator): self
292
    {
293 1
        return static::create(
294 1
            $this->utf8::str_substr_before_last_separator(
295 1
                $this->str,
296 1
                $separator,
297 1
                $this->encoding
298
            )
299
        );
300
    }
301
302
    /**
303
     * Gets the substring before the last occurrence of a separator.
304
     * If no match is found returns new empty Stringy object.
305
     *
306
     * @param string $separator
307
     *
308
     * @return static
309
     */
310 1
    public function beforeLastIgnoreCase(string $separator): self
311
    {
312 1
        return static::create(
313 1
            $this->utf8::str_isubstr_before_last_separator(
314 1
                $this->str,
315 1
                $separator,
316 1
                $this->encoding
317
            )
318
        );
319
    }
320
321
    /**
322
     * Returns the substring between $start and $end, if found, or an empty
323
     * string. An optional offset may be supplied from which to begin the
324
     * search for the start string.
325
     *
326
     * @param string $start  <p>Delimiter marking the start of the substring.</p>
327
     * @param string $end    <p>Delimiter marking the end of the substring.</p>
328
     * @param int    $offset [optional] <p>Index from which to begin the search. Default: 0</p>
329
     *
330
     * @return static
331
     *                <p>Object whose $str is a substring between $start and $end.</p>
332
     */
333 32
    public function between(string $start, string $end, int $offset = null): self
334
    {
335
        /** @noinspection UnnecessaryCastingInspection */
336 32
        $str = $this->utf8::between(
337 32
            $this->str,
338 32
            $start,
339 32
            $end,
340 32
            (int) $offset,
341 32
            $this->encoding
342
        );
343
344 32
        return static::create($str, $this->encoding);
345
    }
346
347
    /**
348
     * Returns a camelCase version of the string. Trims surrounding spaces,
349
     * capitalizes letters following digits, spaces, dashes and underscores,
350
     * and removes spaces, dashes, as well as underscores.
351
     *
352
     * @return static
353
     *                <p>Object with $str in camelCase.</p>
354
     */
355 38
    public function camelize(): self
356
    {
357 38
        return static::create(
358 38
            $this->utf8::str_camelize($this->str, $this->encoding),
359 38
            $this->encoding
360
        );
361
    }
362
363
    /**
364
     * Returns the string with the first letter of each word capitalized,
365
     * except for when the word is a name which shouldn't be capitalized.
366
     *
367
     * @return static
368
     *                <p>Object with $str capitalized.</p>
369
     */
370 39
    public function capitalizePersonalName(): self
371
    {
372 39
        return static::create(
373 39
            $this->utf8::str_capitalize_name($this->str),
374 39
            $this->encoding
375
        );
376
    }
377
378
    /**
379
     * Returns an array consisting of the characters in the string.
380
     *
381
     * @return array
382
     *               <p>An array of string chars.</p>
383
     */
384 8
    public function chars(): array
385
    {
386 8
        return $this->utf8::str_split($this->str);
387
    }
388
389
    /**
390
     * Trims the string and replaces consecutive whitespace characters with a
391
     * single space. This includes tabs and newline characters, as well as
392
     * multibyte whitespace such as the thin space and ideographic space.
393
     *
394
     * @return static
395
     *                <p>Object with a trimmed $str and condensed whitespace.</p>
396
     */
397 26
    public function collapseWhitespace(): self
398
    {
399 26
        return static::create(
400 26
            $this->utf8::collapse_whitespace($this->str),
401 26
            $this->encoding
402
        );
403
    }
404
405
    /**
406
     * Returns true if the string contains $needle, false otherwise. By default
407
     * the comparison is case-sensitive, but can be made insensitive by setting
408
     * $caseSensitive to false.
409
     *
410
     * @param string $needle        <p>Substring to look for.</p>
411
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
412
     *
413
     * @return bool
414
     *              <p>Whether or not $str contains $needle.</p>
415
     */
416 42
    public function contains(string $needle, bool $caseSensitive = true): bool
417
    {
418 42
        return $this->utf8::str_contains(
419 42
            $this->str,
420 42
            $needle,
421 42
            $caseSensitive
422
        );
423
    }
424
425
    /**
426
     * Returns true if the string contains all $needles, false otherwise. By
427
     * default the comparison is case-sensitive, but can be made insensitive by
428
     * setting $caseSensitive to false.
429
     *
430
     * @param array $needles       <p>SubStrings to look for.</p>
431
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
432
     *
433
     * @return bool
434
     *              <p>Whether or not $str contains $needle.</p>
435
     */
436 87
    public function containsAll(array $needles, bool $caseSensitive = true): bool
437
    {
438 87
        return $this->utf8::str_contains_all(
439 87
            $this->str,
440 87
            $needles,
441 87
            $caseSensitive
442
        );
443
    }
444
445
    /**
446
     * Returns true if the string contains any $needles, false otherwise. By
447
     * default the comparison is case-sensitive, but can be made insensitive by
448
     * setting $caseSensitive to false.
449
     *
450
     * @param array $needles       <p>SubStrings to look for.</p>
451
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
452
     *
453
     * @return bool
454
     *              <p>Whether or not $str contains $needle.</p>
455
     */
456 86
    public function containsAny(array $needles, bool $caseSensitive = true): bool
457
    {
458 86
        return $this->utf8::str_contains_any(
459 86
            $this->str,
460 86
            $needles,
461 86
            $caseSensitive
462
        );
463
    }
464
465
    /**
466
     * Returns the length of the string, implementing the countable interface.
467
     *
468
     * @return int
469
     *             <p>The number of characters in the string, given the encoding.</p>
470
     */
471 2
    public function count(): int
472
    {
473 2
        return $this->length();
474
    }
475
476
    /**
477
     * Returns the number of occurrences of $substring in the given string.
478
     * By default, the comparison is case-sensitive, but can be made insensitive
479
     * by setting $caseSensitive to false.
480
     *
481
     * @param string $substring     <p>The substring to search for.</p>
482
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
483
     *
484
     * @return int
485
     */
486 30
    public function countSubstr(string $substring, bool $caseSensitive = true): int
487
    {
488 30
        return $this->utf8::substr_count_simple(
489 30
            $this->str,
490 30
            $substring,
491 30
            $caseSensitive,
492 30
            $this->encoding
493
        );
494
    }
495
496
    /**
497
     * Creates a Stringy object and assigns both str and encoding properties
498
     * the supplied values. $str is cast to a string prior to assignment, and if
499
     * $encoding is not specified, it defaults to mb_internal_encoding(). It
500
     * then returns the initialized object. Throws an InvalidArgumentException
501
     * if the first argument is an array or object without a __toString method.
502
     *
503
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
504
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
505
     *
506
     * @throws \InvalidArgumentException
507
     *                                   <p>if an array or object without a
508
     *                                   __toString method is passed as the first argument</p>
509
     *
510
     * @return static
511
     *                <p>A Stringy object.</p>
512
     */
513 2085
    public static function create($str = '', string $encoding = null): self
514
    {
515 2085
        return new static($str, $encoding);
516
    }
517
518
    /**
519
     * Returns a lowercase and trimmed string separated by dashes. Dashes are
520
     * inserted before uppercase characters (with the exception of the first
521
     * character of the string), and in place of spaces as well as underscores.
522
     *
523
     * @return static
524
     *                <p>Object with a dasherized $str</p>
525
     */
526 38
    public function dasherize(): self
527
    {
528 38
        return static::create(
529 38
            $this->utf8::str_dasherize($this->str),
530 38
            $this->encoding
531
        );
532
    }
533
534
    /**
535
     * Returns a lowercase and trimmed string separated by the given delimiter.
536
     * Delimiters are inserted before uppercase characters (with the exception
537
     * of the first character of the string), and in place of spaces, dashes,
538
     * and underscores. Alpha delimiters are not converted to lowercase.
539
     *
540
     * @param string $delimiter <p>Sequence used to separate parts of the string.</p>
541
     *
542
     * @return static
543
     *                <p>Object with a delimited $str.</p>
544
     */
545 60
    public function delimit(string $delimiter): self
546
    {
547 60
        return static::create(
548 60
            $this->utf8::str_delimit($this->str, $delimiter),
549 60
            $this->encoding
550
        );
551
    }
552
553
    /**
554
     * Returns true if the string ends with $substring, false otherwise. By
555
     * default, the comparison is case-sensitive, but can be made insensitive
556
     * by setting $caseSensitive to false.
557
     *
558
     * @param string $substring     <p>The substring to look for.</p>
559
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
560
     *
561
     * @return bool
562
     *              <p>Whether or not $str ends with $substring.</p>
563
     */
564 22
    public function endsWith(string $substring, bool $caseSensitive = true): bool
565
    {
566 22
        if ($caseSensitive) {
567 14
            return $this->utf8::str_ends_with($this->str, $substring);
568
        }
569
570 8
        return $this->utf8::str_iends_with($this->str, $substring);
571
    }
572
573
    /**
574
     * Returns true if the string ends with any of $substrings, false otherwise.
575
     * By default, the comparison is case-sensitive, but can be made insensitive
576
     * by setting $caseSensitive to false.
577
     *
578
     * @param string[] $substrings    <p>Substrings to look for.</p>
579
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
580
     *
581
     * @return bool
582
     *              <p>Whether or not $str ends with $substring.</p>
583
     */
584 22
    public function endsWithAny(array $substrings, bool $caseSensitive = true): bool
585
    {
586 22
        if ($caseSensitive) {
587 14
            return $this->utf8::str_ends_with_any($this->str, $substrings);
588
        }
589
590 8
        return $this->utf8::str_iends_with_any($this->str, $substrings);
591
    }
592
593
    /**
594
     * Ensures that the string begins with $substring. If it doesn't, it's
595
     * prepended.
596
     *
597
     * @param string $substring <p>The substring to add if not present.</p>
598
     *
599
     * @return static
600
     *                <p>Object with its $str prefixed by the $substring.</p>
601
     */
602 20
    public function ensureLeft(string $substring): self
603
    {
604 20
        return static::create(
605 20
            $this->utf8::str_ensure_left($this->str, $substring),
606 20
            $this->encoding
607
        );
608
    }
609
610
    /**
611
     * Ensures that the string ends with $substring. If it doesn't, it's appended.
612
     *
613
     * @param string $substring <p>The substring to add if not present.</p>
614
     *
615
     * @return static
616
     *                <p>Object with its $str suffixed by the $substring.</p>
617
     */
618 20
    public function ensureRight(string $substring): self
619
    {
620 20
        return static::create(
621 20
            $this->utf8::str_ensure_right($this->str, $substring),
622 20
            $this->encoding
623
        );
624
    }
625
626
    /**
627
     * Create a escape html version of the string via "$this->utf8::htmlspecialchars()".
628
     *
629
     * @return static
630
     */
631 6
    public function escape(): self
632
    {
633 6
        return static::create(
634 6
            $this->utf8::htmlspecialchars(
635 6
                $this->str,
636 6
                \ENT_QUOTES | \ENT_SUBSTITUTE,
637 6
                $this->encoding
638
            ),
639 6
            $this->encoding
640
        );
641
    }
642
643
    /**
644
     * Create an extract from a sentence, so if the search-string was found, it try to centered in the output.
645
     *
646
     * @param string   $search
647
     * @param int|null $length                 [optional] <p>Default: null === text->length / 2</p>
648
     * @param string   $replacerForSkippedText [optional] <p>Default: …</p>
649
     *
650
     * @return static
651
     */
652 1
    public function extractText(string $search = '', int $length = null, string $replacerForSkippedText = '…'): self
653
    {
654 1
        return static::create(
655 1
            $this->utf8::extract_text(
656 1
                $this->str,
657 1
                $search,
658 1
                $length,
659 1
                $replacerForSkippedText,
660 1
                $this->encoding
661
            ),
662 1
            $this->encoding
663
        );
664
    }
665
666
    /**
667
     * Returns the first $n characters of the string.
668
     *
669
     * @param int $n <p>Number of characters to retrieve from the start.</p>
670
     *
671
     * @return static
672
     *                <p>Object with its $str being the first $n chars.</p>
673
     */
674 25
    public function first(int $n): self
675
    {
676 25
        return static::create(
677 25
            $this->utf8::first_char($this->str, $n, $this->encoding),
678 25
            $this->encoding
679
        );
680
    }
681
682
    /**
683
     * Returns the encoding used by the Stringy object.
684
     *
685
     * @return string
686
     *                <p>The current value of the $encoding property.</p>
687
     */
688 5
    public function getEncoding(): string
689
    {
690 5
        return $this->encoding;
691
    }
692
693
    /**
694
     * Returns a new ArrayIterator, thus implementing the IteratorAggregate
695
     * interface. The ArrayIterator's constructor is passed an array of chars
696
     * in the multibyte string. This enables the use of foreach with instances
697
     * of Stringy\Stringy.
698
     *
699
     * @return \ArrayIterator
700
     *                        <p>An iterator for the characters in the string.</p>
701
     */
702 2
    public function getIterator(): \ArrayIterator
703
    {
704 2
        return new \ArrayIterator($this->chars());
705
    }
706
707
    /**
708
     * Returns true if the string contains a lower case char, false otherwise.
709
     *
710
     * @return bool
711
     *              <p>Whether or not the string contains a lower case character.</p>
712
     */
713 24
    public function hasLowerCase(): bool
714
    {
715 24
        return $this->utf8::has_lowercase($this->str);
716
    }
717
718
    /**
719
     * Returns true if the string contains an upper case char, false otherwise.
720
     *
721
     * @return bool
722
     *              <p>Whether or not the string contains an upper case character.</p>
723
     */
724 24
    public function hasUpperCase(): bool
725
    {
726 24
        return $this->utf8::has_uppercase($this->str);
727
    }
728
729
    /**
730
     * Convert all HTML entities to their applicable characters.
731
     *
732
     * @param int $flags [optional] <p>
733
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
734
     *                   which document type to use. The default is ENT_COMPAT.
735
     *                   <table>
736
     *                   Available <i>flags</i> constants
737
     *                   <tr valign="top">
738
     *                   <td>Constant Name</td>
739
     *                   <td>Description</td>
740
     *                   </tr>
741
     *                   <tr valign="top">
742
     *                   <td><b>ENT_COMPAT</b></td>
743
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
744
     *                   </tr>
745
     *                   <tr valign="top">
746
     *                   <td><b>ENT_QUOTES</b></td>
747
     *                   <td>Will convert both double and single quotes.</td>
748
     *                   </tr>
749
     *                   <tr valign="top">
750
     *                   <td><b>ENT_NOQUOTES</b></td>
751
     *                   <td>Will leave both double and single quotes unconverted.</td>
752
     *                   </tr>
753
     *                   <tr valign="top">
754
     *                   <td><b>ENT_HTML401</b></td>
755
     *                   <td>
756
     *                   Handle code as HTML 4.01.
757
     *                   </td>
758
     *                   </tr>
759
     *                   <tr valign="top">
760
     *                   <td><b>ENT_XML1</b></td>
761
     *                   <td>
762
     *                   Handle code as XML 1.
763
     *                   </td>
764
     *                   </tr>
765
     *                   <tr valign="top">
766
     *                   <td><b>ENT_XHTML</b></td>
767
     *                   <td>
768
     *                   Handle code as XHTML.
769
     *                   </td>
770
     *                   </tr>
771
     *                   <tr valign="top">
772
     *                   <td><b>ENT_HTML5</b></td>
773
     *                   <td>
774
     *                   Handle code as HTML 5.
775
     *                   </td>
776
     *                   </tr>
777
     *                   </table>
778
     *                   </p>
779
     *
780
     * @return static
781
     *                <p>Object with the resulting $str after being html decoded.</p>
782
     */
783 10 View Code Duplication
    public function htmlDecode(int $flags = \ENT_COMPAT): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
784
    {
785 10
        return static::create(
786 10
            $this->utf8::html_entity_decode(
787 10
                $this->str,
788 10
                $flags,
789 10
                $this->encoding
790
            ),
791 10
            $this->encoding
792
        );
793
    }
794
795
    /**
796
     * Convert all applicable characters to HTML entities.
797
     *
798
     * @param int $flags [optional] <p>
799
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
800
     *                   which document type to use. The default is ENT_COMPAT.
801
     *                   <table>
802
     *                   Available <i>flags</i> constants
803
     *                   <tr valign="top">
804
     *                   <td>Constant Name</td>
805
     *                   <td>Description</td>
806
     *                   </tr>
807
     *                   <tr valign="top">
808
     *                   <td><b>ENT_COMPAT</b></td>
809
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
810
     *                   </tr>
811
     *                   <tr valign="top">
812
     *                   <td><b>ENT_QUOTES</b></td>
813
     *                   <td>Will convert both double and single quotes.</td>
814
     *                   </tr>
815
     *                   <tr valign="top">
816
     *                   <td><b>ENT_NOQUOTES</b></td>
817
     *                   <td>Will leave both double and single quotes unconverted.</td>
818
     *                   </tr>
819
     *                   <tr valign="top">
820
     *                   <td><b>ENT_HTML401</b></td>
821
     *                   <td>
822
     *                   Handle code as HTML 4.01.
823
     *                   </td>
824
     *                   </tr>
825
     *                   <tr valign="top">
826
     *                   <td><b>ENT_XML1</b></td>
827
     *                   <td>
828
     *                   Handle code as XML 1.
829
     *                   </td>
830
     *                   </tr>
831
     *                   <tr valign="top">
832
     *                   <td><b>ENT_XHTML</b></td>
833
     *                   <td>
834
     *                   Handle code as XHTML.
835
     *                   </td>
836
     *                   </tr>
837
     *                   <tr valign="top">
838
     *                   <td><b>ENT_HTML5</b></td>
839
     *                   <td>
840
     *                   Handle code as HTML 5.
841
     *                   </td>
842
     *                   </tr>
843
     *                   </table>
844
     *                   </p>
845
     *
846
     * @return static
847
     *                <p>Object with the resulting $str after being html encoded.</p>
848
     */
849 10 View Code Duplication
    public function htmlEncode(int $flags = \ENT_COMPAT): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
850
    {
851 10
        return static::create(
852 10
            $this->utf8::htmlentities(
853 10
                $this->str,
854 10
                $flags,
855 10
                $this->encoding
856
            ),
857 10
            $this->encoding
858
        );
859
    }
860
861
    /**
862
     * Capitalizes the first word of the string, replaces underscores with
863
     * spaces, and strips '_id'.
864
     *
865
     * @return static
866
     *                <p>Object with a humanized $str.</p>
867
     */
868 6
    public function humanize(): self
869
    {
870 6
        return static::create(
871 6
            $this->utf8::str_humanize($this->str),
872 6
            $this->encoding
873
        );
874
    }
875
876
    /**
877
     * Returns the index of the first occurrence of $needle in the string,
878
     * and false if not found. Accepts an optional offset from which to begin
879
     * the search.
880
     *
881
     * @param string $needle <p>Substring to look for.</p>
882
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
883
     *
884
     * @return false|int
885
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
886
     */
887 20
    public function indexOf(string $needle, int $offset = 0)
888
    {
889 20
        return $this->utf8::strpos(
890 20
            $this->str,
891 20
            $needle,
892 20
            $offset,
893 20
            $this->encoding
894
        );
895
    }
896
897
    /**
898
     * Returns the index of the first occurrence of $needle in the string,
899
     * and false if not found. Accepts an optional offset from which to begin
900
     * the search.
901
     *
902
     * @param string $needle <p>Substring to look for.</p>
903
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
904
     *
905
     * @return false|int
906
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
907
     */
908
    public function indexOfIgnoreCase(string $needle, int $offset = 0)
909
    {
910
        return $this->utf8::stripos(
911
            $this->str,
912
            $needle,
913
            $offset,
914
            $this->encoding
915
        );
916
    }
917
918
    /**
919
     * Returns the index of the last occurrence of $needle in the string,
920
     * and false if not found. Accepts an optional offset from which to begin
921
     * the search. Offsets may be negative to count from the last character
922
     * in the string.
923
     *
924
     * @param string $needle <p>Substring to look for.</p>
925
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
926
     *
927
     * @return false|int
928
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
929
     */
930 20
    public function indexOfLast(string $needle, int $offset = 0)
931
    {
932 20
        return $this->utf8::strrpos(
933 20
            $this->str,
934 20
            $needle,
935 20
            $offset,
936 20
            $this->encoding
937
        );
938
    }
939
940
    /**
941
     * Returns the index of the last occurrence of $needle in the string,
942
     * and false if not found. Accepts an optional offset from which to begin
943
     * the search. Offsets may be negative to count from the last character
944
     * in the string.
945
     *
946
     * @param string $needle <p>Substring to look for.</p>
947
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
948
     *
949
     * @return false|int
950
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
951
     */
952
    public function indexOfLastIgnoreCase(string $needle, int $offset = 0)
953
    {
954
        return $this->utf8::strripos(
955
            $this->str,
956
            $needle,
957
            $offset,
958
            $this->encoding
959
        );
960
    }
961
962
    /**
963
     * Inserts $substring into the string at the $index provided.
964
     *
965
     * @param string $substring <p>String to be inserted.</p>
966
     * @param int    $index     <p>The index at which to insert the substring.</p>
967
     *
968
     * @return static
969
     *                <p>Object with the resulting $str after the insertion.</p>
970
     */
971 16
    public function insert(string $substring, int $index): self
972
    {
973 16
        return static::create(
974 16
            $this->utf8::str_insert(
975 16
                $this->str,
976 16
                $substring,
977 16
                $index,
978 16
                $this->encoding
979
            ),
980 16
            $this->encoding
981
        );
982
    }
983
984
    /**
985
     * Returns true if the string contains the $pattern, otherwise false.
986
     *
987
     * WARNING: Asterisks ("*") are translated into (".*") zero-or-more regular
988
     * expression wildcards.
989
     *
990
     * @credit Originally from Laravel, thanks Taylor.
991
     *
992
     * @param string $pattern <p>The string or pattern to match against.</p>
993
     *
994
     * @return bool
995
     *              <p>Whether or not we match the provided pattern.</p>
996
     */
997 13
    public function is(string $pattern): bool
998
    {
999 13
        if ($this->toString() === $pattern) {
1000 1
            return true;
1001
        }
1002
1003 12
        $quotedPattern = \preg_quote($pattern, '/');
1004 12
        $replaceWildCards = \str_replace('\*', '.*', $quotedPattern);
1005
1006 12
        return $this->matchesPattern('^' . $replaceWildCards . '\z');
1007
    }
1008
1009
    /**
1010
     * Returns true if the string contains only alphabetic chars, false otherwise.
1011
     *
1012
     * @return bool
1013
     *              <p>Whether or not $str contains only alphabetic chars.</p>
1014
     */
1015 20
    public function isAlpha(): bool
1016
    {
1017 20
        return $this->utf8::is_alpha($this->str);
1018
    }
1019
1020
    /**
1021
     * Returns true if the string contains only alphabetic and numeric chars, false otherwise.
1022
     *
1023
     * @return bool
1024
     *              <p>Whether or not $str contains only alphanumeric chars.</p>
1025
     */
1026 26
    public function isAlphanumeric(): bool
1027
    {
1028 26
        return $this->utf8::is_alphanumeric($this->str);
1029
    }
1030
1031
    /**
1032
     * Returns true if the string is base64 encoded, false otherwise.
1033
     *
1034
     * @param bool $emptyStringIsValid
1035
     *
1036
     * @return bool
1037
     *              <p>Whether or not $str is base64 encoded.</p>
1038
     */
1039 14
    public function isBase64($emptyStringIsValid = true): bool
1040
    {
1041 14
        return $this->utf8::is_base64($this->str, $emptyStringIsValid);
1042
    }
1043
1044
    /**
1045
     * Returns true if the string contains only whitespace chars, false otherwise.
1046
     *
1047
     * @return bool
1048
     *              <p>Whether or not $str contains only whitespace characters.</p>
1049
     */
1050 30
    public function isBlank(): bool
1051
    {
1052 30
        return $this->utf8::is_blank($this->str);
1053
    }
1054
1055
    /**
1056
     * Returns true if the string contains a valid E-Mail address, false otherwise.
1057
     *
1058
     * @param bool $useExampleDomainCheck   [optional] <p>Default: false</p>
1059
     * @param bool $useTypoInDomainCheck    [optional] <p>Default: false</p>
1060
     * @param bool $useTemporaryDomainCheck [optional] <p>Default: false</p>
1061
     * @param bool $useDnsCheck             [optional] <p>Default: false</p>
1062
     *
1063
     * @return bool
1064
     *              <p>Whether or not $str contains a valid E-Mail address.</p>
1065
     */
1066 1
    public function isEmail(bool $useExampleDomainCheck = false, bool $useTypoInDomainCheck = false, bool $useTemporaryDomainCheck = false, bool $useDnsCheck = false): bool
1067
    {
1068 1
        return EmailCheck::isValid($this->str, $useExampleDomainCheck, $useTypoInDomainCheck, $useTemporaryDomainCheck, $useDnsCheck);
1069
    }
1070
1071
    /**
1072
     * Determine whether the string is considered to be empty.
1073
     *
1074
     * A variable is considered empty if it does not exist or if its value equals FALSE.
1075
     * empty() does not generate a warning if the variable does not exist.
1076
     *
1077
     * @return bool
1078
     *              <p>Whether or not $str is empty().</p>
1079
     */
1080
    public function isEmpty(): bool
1081
    {
1082
        return $this->utf8::is_empty($this->str);
1083
    }
1084
1085
    /**
1086
     * Returns true if the string contains only hexadecimal chars, false otherwise.
1087
     *
1088
     * @return bool
1089
     *              <p>Whether or not $str contains only hexadecimal chars.</p>
1090
     */
1091 26
    public function isHexadecimal(): bool
1092
    {
1093 26
        return $this->utf8::is_hexadecimal($this->str);
1094
    }
1095
1096
    /**
1097
     * Returns true if the string contains HTML-Tags, false otherwise.
1098
     *
1099
     * @return bool
1100
     *              <p>Whether or not $str contains HTML-Tags.</p>
1101
     */
1102 1
    public function isHtml(): bool
1103
    {
1104 1
        return $this->utf8::is_html($this->str);
1105
    }
1106
1107
    /**
1108
     * Returns true if the string is JSON, false otherwise. Unlike json_decode
1109
     * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
1110
     * in that an empty string is not considered valid JSON.
1111
     *
1112
     * @param bool $onlyArrayOrObjectResultsAreValid
1113
     *
1114
     * @return bool
1115
     *              <p>Whether or not $str is JSON.</p>
1116
     */
1117 40
    public function isJson($onlyArrayOrObjectResultsAreValid = false): bool
1118
    {
1119 40
        return $this->utf8::is_json($this->str, $onlyArrayOrObjectResultsAreValid);
1120
    }
1121
1122
    /**
1123
     * Returns true if the string contains only lower case chars, false otherwise.
1124
     *
1125
     * @return bool
1126
     *              <p>Whether or not $str contains only lower case characters.</p>
1127
     */
1128 16
    public function isLowerCase(): bool
1129
    {
1130 16
        return $this->utf8::is_lowercase($this->str);
1131
    }
1132
1133
    /**
1134
     * Returns true if the string is serialized, false otherwise.
1135
     *
1136
     * @return bool
1137
     *              <p>Whether or not $str is serialized.</p>
1138
     */
1139 14
    public function isSerialized(): bool
1140
    {
1141 14
        return $this->utf8::is_serialized($this->str);
1142
    }
1143
1144
    /**
1145
     * Returns true if the string contains only lower case chars, false
1146
     * otherwise.
1147
     *
1148
     * @return bool
1149
     *              <p>Whether or not $str contains only lower case characters.</p>
1150
     */
1151 16
    public function isUpperCase(): bool
1152
    {
1153 16
        return $this->utf8::is_uppercase($this->str);
1154
    }
1155
1156
    /**
1157
     * Returns the last $n characters of the string.
1158
     *
1159
     * @param int $n <p>Number of characters to retrieve from the end.</p>
1160
     *
1161
     * @return static
1162
     *                <p>Object with its $str being the last $n chars.</p>
1163
     */
1164 24
    public function last(int $n): self
1165
    {
1166 24
        return static::create(
1167 24
            $this->utf8::str_last_char(
1168 24
                $this->str,
1169 24
                $n,
1170 24
                $this->encoding
1171
            ),
1172 24
            $this->encoding
1173
        );
1174
    }
1175
1176
    /**
1177
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
1178
     * If no match is found returns new empty Stringy object.
1179
     *
1180
     * @param string $needle       <p>The string to look for.</p>
1181
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
1182
     *
1183
     * @return static
1184
     */
1185 2 View Code Duplication
    public function lastSubstringOf(string $needle, bool $beforeNeedle = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1186
    {
1187 2
        return static::create(
1188 2
            $this->utf8::str_substr_last($this->str, $needle, $beforeNeedle, $this->encoding),
1189 2
            $this->encoding
1190
        );
1191
    }
1192
1193
    /**
1194
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
1195
     * If no match is found returns new empty Stringy object.
1196
     *
1197
     * @param string $needle       <p>The string to look for.</p>
1198
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
1199
     *
1200
     * @return static
1201
     */
1202 1 View Code Duplication
    public function lastSubstringOfIgnoreCase(string $needle, bool $beforeNeedle = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1203
    {
1204 1
        return static::create(
1205 1
            $this->utf8::str_isubstr_last($this->str, $needle, $beforeNeedle, $this->encoding),
1206 1
            $this->encoding
1207
        );
1208
    }
1209
1210
    /**
1211
     * Returns the length of the string.
1212
     *
1213
     * @return int
1214
     *             <p>The number of characters in $str given the encoding.</p>
1215
     */
1216 11
    public function length(): int
1217
    {
1218 11
        return (int) $this->utf8::strlen($this->str, $this->encoding);
1219
    }
1220
1221
    /**
1222
     * Line-Wrap the string after $limit, but also after the next word.
1223
     *
1224
     * @param int $limit
1225
     *
1226
     * @return static
1227
     */
1228 1
    public function lineWrapAfterWord(int $limit): self
1229
    {
1230 1
        return static::create(
1231 1
            $this->utf8::wordwrap_per_line($this->str, $limit),
1232 1
            $this->encoding
1233
        );
1234
    }
1235
1236
    /**
1237
     * Splits on newlines and carriage returns, returning an array of Stringy
1238
     * objects corresponding to the lines in the string.
1239
     *
1240
     * @return static[]
1241
     *                  <p>An array of Stringy objects.</p>
1242
     */
1243 32
    public function lines(): array
1244
    {
1245 32
        $array = $this->utf8::str_to_lines($this->str);
1246 32
        foreach ($array as $i => &$value) {
1247 32
            $value = static::create($value, $this->encoding);
1248
        }
1249
1250 32
        return $array;
1251
    }
1252
1253
    /**
1254
     * Returns the longest common prefix between the string and $otherStr.
1255
     *
1256
     * @param string $otherStr <p>Second string for comparison.</p>
1257
     *
1258
     * @return static
1259
     *                <p>Object with its $str being the longest common prefix.</p>
1260
     */
1261 20
    public function longestCommonPrefix(string $otherStr): self
1262
    {
1263 20
        return static::create(
1264 20
            $this->utf8::str_longest_common_prefix(
1265 20
                $this->str,
1266 20
                $otherStr,
1267 20
                $this->encoding
1268
            ),
1269 20
            $this->encoding
1270
        );
1271
    }
1272
1273
    /**
1274
     * Returns the longest common substring between the string and $otherStr.
1275
     * In the case of ties, it returns that which occurs first.
1276
     *
1277
     * @param string $otherStr <p>Second string for comparison.</p>
1278
     *
1279
     * @return static
1280
     *                <p>Object with its $str being the longest common substring.</p>
1281
     */
1282 20
    public function longestCommonSubstring(string $otherStr): self
1283
    {
1284 20
        return static::create(
1285 20
            $this->utf8::str_longest_common_substring(
1286 20
                $this->str,
1287 20
                $otherStr,
1288 20
                $this->encoding
1289
            ),
1290 20
            $this->encoding
1291
        );
1292
    }
1293
1294
    /**
1295
     * Returns the longest common suffix between the string and $otherStr.
1296
     *
1297
     * @param string $otherStr <p>Second string for comparison.</p>
1298
     *
1299
     * @return static
1300
     *                <p>Object with its $str being the longest common suffix.</p>
1301
     */
1302 20
    public function longestCommonSuffix(string $otherStr): self
1303
    {
1304 20
        return static::create(
1305 20
            $this->utf8::str_longest_common_suffix(
1306 20
                $this->str,
1307 20
                $otherStr,
1308 20
                $this->encoding
1309
            ),
1310 20
            $this->encoding
1311
        );
1312
    }
1313
1314
    /**
1315
     * Converts the first character of the string to lower case.
1316
     *
1317
     * @return static
1318
     *                <p>Object with the first character of $str being lower case.</p>
1319
     */
1320 10
    public function lowerCaseFirst(): self
1321
    {
1322 10
        return static::create(
1323 10
            $this->utf8::lcfirst($this->str, $this->encoding),
1324 10
            $this->encoding
1325
        );
1326
    }
1327
1328
    /**
1329
     * Returns whether or not a character exists at an index. Offsets may be
1330
     * negative to count from the last character in the string. Implements
1331
     * part of the ArrayAccess interface.
1332
     *
1333
     * @param int $offset <p>The index to check.</p>
1334
     *
1335
     * @return bool
1336
     *              <p>Whether or not the index exists.</p>
1337
     */
1338 12
    public function offsetExists($offset): bool
1339
    {
1340 12
        return $this->utf8::str_offset_exists(
1341 12
            $this->str,
1342 12
            $offset,
1343 12
            $this->encoding
1344
        );
1345
    }
1346
1347
    /**
1348
     * Returns the character at the given index. Offsets may be negative to
1349
     * count from the last character in the string. Implements part of the
1350
     * ArrayAccess interface, and throws an OutOfBoundsException if the index
1351
     * does not exist.
1352
     *
1353
     * @param int $offset <p>The <strong>index</strong> from which to retrieve the char.</p>
1354
     *
1355
     *@throws \OutOfBoundsException
1356
     *                               <p>If the positive or negative offset does not exist.</p>
1357
     *
1358
     * @return string
1359
     *                <p>The character at the specified index.</p>
1360
     */
1361 4
    public function offsetGet($offset): string
1362
    {
1363 4
        return $this->utf8::str_offset_get($this->str, $offset, $this->encoding);
1364
    }
1365
1366
    /**
1367
     * Implements part of the ArrayAccess interface, but throws an exception
1368
     * when called. This maintains the immutability of Stringy objects.
1369
     *
1370
     * @param int   $offset <p>The index of the character.</p>
1371
     * @param mixed $value  <p>Value to set.</p>
1372
     *
1373
     * @throws \Exception
1374
     *                    <p>When called.</p>
1375
     */
1376 2
    public function offsetSet($offset, $value)
1377
    {
1378
        // Stringy is immutable, cannot directly set char
1379
        /** @noinspection ThrowRawExceptionInspection */
1380 2
        throw new \Exception('Stringy object is immutable, cannot modify char');
1381
    }
1382
1383
    /**
1384
     * Implements part of the ArrayAccess interface, but throws an exception
1385
     * when called. This maintains the immutability of Stringy objects.
1386
     *
1387
     * @param int $offset <p>The index of the character.</p>
1388
     *
1389
     * @throws \Exception
1390
     *                    <p>When called.</p>
1391
     */
1392 2
    public function offsetUnset($offset)
1393
    {
1394
        // Don't allow directly modifying the string
1395
        /** @noinspection ThrowRawExceptionInspection */
1396 2
        throw new \Exception('Stringy object is immutable, cannot unset char');
1397
    }
1398
1399
    /**
1400
     * Pads the string to a given length with $padStr. If length is less than
1401
     * or equal to the length of the string, no padding takes places. The
1402
     * default string used for padding is a space, and the default type (one of
1403
     * 'left', 'right', 'both') is 'right'. Throws an InvalidArgumentException
1404
     * if $padType isn't one of those 3 values.
1405
     *
1406
     * @param int    $length  <p>Desired string length after padding.</p>
1407
     * @param string $padStr  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
1408
     * @param string $padType [optional] <p>One of 'left', 'right', 'both'. Default: 'right'</p>
1409
     *
1410
     * @throws \InvalidArgumentException
1411
     *                                   <p>If $padType isn't one of 'right', 'left' or 'both'.</p>
1412
     *
1413
     * @return static
1414
     *                <p>Object with a padded $str.</p>
1415
     */
1416 26
    public function pad(int $length, string $padStr = ' ', string $padType = 'right'): self
1417
    {
1418 26
        return static::create(
1419 26
            $this->utf8::str_pad(
1420 26
                $this->str,
1421 26
                $length,
1422 26
                $padStr,
1423 26
                $padType,
1424 26
                $this->encoding
1425
            )
1426
        );
1427
    }
1428
1429
    /**
1430
     * Returns a new string of a given length such that both sides of the
1431
     * string are padded. Alias for pad() with a $padType of 'both'.
1432
     *
1433
     * @param int    $length <p>Desired string length after padding.</p>
1434
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
1435
     *
1436
     * @return static
1437
     *                <p>String with padding applied.</p>
1438
     */
1439 22
    public function padBoth(int $length, string $padStr = ' '): self
1440
    {
1441 22
        return static::create(
1442 22
            $this->utf8::str_pad_both(
1443 22
                $this->str,
1444 22
                $length,
1445 22
                $padStr,
1446 22
                $this->encoding
1447
            )
1448
        );
1449
    }
1450
1451
    /**
1452
     * Returns a new string of a given length such that the beginning of the
1453
     * string is padded. Alias for pad() with a $padType of 'left'.
1454
     *
1455
     * @param int    $length <p>Desired string length after padding.</p>
1456
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
1457
     *
1458
     * @return static
1459
     *                <p>String with left padding.</p>
1460
     */
1461 14
    public function padLeft(int $length, string $padStr = ' '): self
1462
    {
1463 14
        return static::create(
1464 14
            $this->utf8::str_pad_left(
1465 14
                $this->str,
1466 14
                $length,
1467 14
                $padStr,
1468 14
                $this->encoding
1469
            )
1470
        );
1471
    }
1472
1473
    /**
1474
     * Returns a new string of a given length such that the end of the string
1475
     * is padded. Alias for pad() with a $padType of 'right'.
1476
     *
1477
     * @param int    $length <p>Desired string length after padding.</p>
1478
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
1479
     *
1480
     * @return static
1481
     *                <p>String with right padding.</p>
1482
     */
1483 14
    public function padRight(int $length, string $padStr = ' '): self
1484
    {
1485 14
        return static::create(
1486 14
            $this->utf8::str_pad_right(
1487 14
                $this->str,
1488 14
                $length,
1489 14
                $padStr,
1490 14
                $this->encoding
1491
            )
1492
        );
1493
    }
1494
1495
    /**
1496
     * Returns a new string starting with $string.
1497
     *
1498
     * @param string $string <p>The string to append.</p>
1499
     *
1500
     * @return static
1501
     *                <p>Object with appended $string.</p>
1502
     */
1503 4
    public function prepend(string $string): self
1504
    {
1505 4
        return static::create($string . $this->str, $this->encoding);
1506
    }
1507
1508
    /**
1509
     * Replaces all occurrences of $pattern in $str by $replacement.
1510
     *
1511
     * @param string $pattern     <p>The regular expression pattern.</p>
1512
     * @param string $replacement <p>The string to replace with.</p>
1513
     * @param string $options     [optional] <p>Matching conditions to be used.</p>
1514
     * @param string $delimiter   [optional] <p>Delimiter the the regex. Default: '/'</p>
1515
     *
1516
     * @return static
1517
     *                <p>Object with the result2ing $str after the replacements.</p>
1518
     */
1519 19
    public function regexReplace(string $pattern, string $replacement, string $options = '', string $delimiter = '/'): self
1520
    {
1521 19
        return static::create(
1522 19
            $this->utf8::regex_replace(
1523 19
                $this->str,
1524 19
                $pattern,
1525 19
                $replacement,
1526 19
                $options,
1527 19
                $delimiter
1528
            ),
1529 19
            $this->encoding
1530
        );
1531
    }
1532
1533
    /**
1534
     * Remove html via "strip_tags()" from the string.
1535
     *
1536
     * @param string $allowableTags [optional] <p>You can use the optional second parameter to specify tags which should
1537
     *                              not be stripped. Default: null
1538
     *                              </p>
1539
     *
1540
     * @return static
1541
     */
1542 6
    public function removeHtml(string $allowableTags = null): self
1543
    {
1544 6
        return static::create(
1545 6
            $this->utf8::remove_html($this->str, $allowableTags . ''),
1546 6
            $this->encoding
1547
        );
1548
    }
1549
1550
    /**
1551
     * Remove all breaks [<br> | \r\n | \r | \n | ...] from the string.
1552
     *
1553
     * @param string $replacement [optional] <p>Default is a empty string.</p>
1554
     *
1555
     * @return static
1556
     */
1557 6
    public function removeHtmlBreak(string $replacement = ''): self
1558
    {
1559 6
        return static::create(
1560 6
            $this->utf8::remove_html_breaks($this->str, $replacement),
1561 6
            $this->encoding
1562
        );
1563
    }
1564
1565
    /**
1566
     * Returns a new string with the prefix $substring removed, if present.
1567
     *
1568
     * @param string $substring <p>The prefix to remove.</p>
1569
     *
1570
     * @return static
1571
     *                <p>Object having a $str without the prefix $substring.</p>
1572
     */
1573 24
    public function removeLeft(string $substring): self
1574
    {
1575 24
        return static::create(
1576 24
            $this->utf8::remove_left($this->str, $substring, $this->encoding),
1577 24
            $this->encoding
1578
        );
1579
    }
1580
1581
    /**
1582
     * Returns a new string with the suffix $substring removed, if present.
1583
     *
1584
     * @param string $substring <p>The suffix to remove.</p>
1585
     *
1586
     * @return static
1587
     *                <p>Object having a $str without the suffix $substring.</p>
1588
     */
1589 24
    public function removeRight(string $substring): self
1590
    {
1591 24
        return static::create(
1592 24
            $this->utf8::remove_right($this->str, $substring, $this->encoding),
1593 24
            $this->encoding
1594
        );
1595
    }
1596
1597
    /**
1598
     * Try to remove all XSS-attacks from the string.
1599
     *
1600
     * @return static
1601
     */
1602 6
    public function removeXss(): self
1603
    {
1604 6
        static $antiXss = null;
1605
1606 6
        if ($antiXss === null) {
1607 1
            $antiXss = new AntiXSS();
1608
        }
1609
1610 6
        $str = $antiXss->xss_clean($this->str);
1611
1612 6
        return static::create($str, $this->encoding);
1613
    }
1614
1615
    /**
1616
     * Returns a repeated string given a multiplier.
1617
     *
1618
     * @param int $multiplier <p>The number of times to repeat the string.</p>
1619
     *
1620
     * @return static
1621
     *                <p>Object with a repeated str.</p>
1622
     */
1623 14
    public function repeat(int $multiplier): self
1624
    {
1625 14
        return static::create(
1626 14
            \str_repeat($this->str, $multiplier),
1627 14
            $this->encoding
1628
        );
1629
    }
1630
1631
    /**
1632
     * Replaces all occurrences of $search in $str by $replacement.
1633
     *
1634
     * @param string $search        <p>The needle to search for.</p>
1635
     * @param string $replacement   <p>The string to replace with.</p>
1636
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1637
     *
1638
     * @return static
1639
     *                <p>Object with the resulting $str after the replacements.</p>
1640
     */
1641 45
    public function replace(string $search, string $replacement, bool $caseSensitive = true): self
1642
    {
1643 45
        if ($search === '' && $replacement === '') {
1644 10
            return static::create($this->str, $this->encoding);
1645
        }
1646
1647 35
        if ($this->str === '' && $search === '') {
1648 2
            return static::create($replacement, $this->encoding);
1649
        }
1650
1651 33
        if ($caseSensitive) {
1652 28
            return static::create(
1653 28
                $this->utf8::str_replace($search, $replacement, $this->str),
1654 28
                $this->encoding
1655
            );
1656
        }
1657
1658 5
        return static::create(
1659 5
            $this->utf8::str_ireplace($search, $replacement, $this->str),
1660 5
            $this->encoding
1661
        );
1662
    }
1663
1664
    /**
1665
     * Replaces all occurrences of $search in $str by $replacement.
1666
     *
1667
     * @param array        $search        <p>The elements to search for.</p>
1668
     * @param array|string $replacement   <p>The string to replace with.</p>
1669
     * @param bool         $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1670
     *
1671
     * @return static
1672
     *                <p>Object with the resulting $str after the replacements.</p>
1673
     */
1674 30
    public function replaceAll(array $search, $replacement, bool $caseSensitive = true): self
1675
    {
1676 30
        if ($caseSensitive) {
1677 23
            return static::create(
1678 23
                $this->utf8::str_replace($search, $replacement, $this->str),
1679 23
                $this->encoding
1680
            );
1681
        }
1682
1683 7
        return static::create(
1684 7
            $this->utf8::str_ireplace($search, $replacement, $this->str),
1685 7
            $this->encoding
1686
        );
1687
    }
1688
1689
    /**
1690
     * Replaces first occurrences of $search from the beginning of string with $replacement.
1691
     *
1692
     * @param string $search      <p>The string to search for.</p>
1693
     * @param string $replacement <p>The replacement.</p>
1694
     *
1695
     * @return static
1696
     *                <p>Object with the resulting $str after the replacements.</p>
1697
     */
1698 16
    public function replaceFirst(string $search, string $replacement): self
1699
    {
1700 16
        return static::create(
1701 16
            $this->utf8::str_replace_first($search, $replacement, $this->str),
1702 16
            $this->encoding
1703
        );
1704
    }
1705
1706
    /**
1707
     * Replaces last occurrences of $search from the ending of string with $replacement.
1708
     *
1709
     * @param string $search      <p>The string to search for.</p>
1710
     * @param string $replacement <p>The replacement.</p>
1711
     *
1712
     * @return static
1713
     *                <p>Object with the resulting $str after the replacements.</p>
1714
     */
1715 15
    public function replaceLast(string $search, string $replacement): self
1716
    {
1717 15
        return static::create(
1718 15
            $this->utf8::str_replace_last($search, $replacement, $this->str),
1719 15
            $this->encoding
1720
        );
1721
    }
1722
1723
    /**
1724
     * Replaces all occurrences of $search from the beginning of string with $replacement.
1725
     *
1726
     * @param string $search      <p>The string to search for.</p>
1727
     * @param string $replacement <p>The replacement.</p>
1728
     *
1729
     * @return static
1730
     *                <p>Object with the resulting $str after the replacements.</p>
1731
     */
1732 16
    public function replaceBeginning(string $search, string $replacement): self
1733
    {
1734 16
        return static::create(
1735 16
            $this->utf8::str_replace_beginning($this->str, $search, $replacement),
1736 16
            $this->encoding
1737
        );
1738
    }
1739
1740
    /**
1741
     * Replaces all occurrences of $search from the ending of string with $replacement.
1742
     *
1743
     * @param string $search      <p>The string to search for.</p>
1744
     * @param string $replacement <p>The replacement.</p>
1745
     *
1746
     * @return static
1747
     *                <p>Object with the resulting $str after the replacements.</p>
1748
     */
1749 16
    public function replaceEnding(string $search, string $replacement): self
1750
    {
1751 16
        return static::create(
1752 16
            $this->utf8::str_replace_ending($this->str, $search, $replacement),
1753 16
            $this->encoding
1754
        );
1755
    }
1756
1757
    /**
1758
     * Returns a reversed string. A multibyte version of strrev().
1759
     *
1760
     * @return static
1761
     *                <p>Object with a reversed $str.</p>
1762
     */
1763 10
    public function reverse(): self
1764
    {
1765 10
        return static::create($this->utf8::strrev($this->str), $this->encoding);
1766
    }
1767
1768
    /**
1769
     * Truncates the string to a given length, while ensuring that it does not
1770
     * split words. If $substring is provided, and truncating occurs, the
1771
     * string is further truncated so that the substring may be appended without
1772
     * exceeding the desired length.
1773
     *
1774
     * @param int    $length                          <p>Desired length of the truncated string.</p>
1775
     * @param string $substring                       [optional] <p>The substring to append if it can fit. Default: ''</p>
1776
     * @param bool   $ignoreDoNotSplitWordsForOneWord
1777
     *
1778
     * @return static
1779
     *                <p>Object with the resulting $str after truncating.</p>
1780
     */
1781 45
    public function safeTruncate(int $length, string $substring = '', bool $ignoreDoNotSplitWordsForOneWord = true): self
1782
    {
1783 45
        return static::create(
1784 45
            $this->utf8::str_truncate_safe(
1785 45
                $this->str,
1786 45
                $length,
1787 45
                $substring,
1788 45
                $this->encoding,
1789 45
                $ignoreDoNotSplitWordsForOneWord
1790
            ),
1791 45
            $this->encoding
1792
        );
1793
    }
1794
1795
    /**
1796
     * Shorten the string after $length, but also after the next word.
1797
     *
1798
     * @param int    $length
1799
     * @param string $strAddOn [optional] <p>Default: '…'</p>
1800
     *
1801
     * @return static
1802
     */
1803 4
    public function shortenAfterWord(int $length, string $strAddOn = '…'): self
1804
    {
1805 4
        return static::create(
1806 4
            $this->utf8::str_limit_after_word($this->str, $length, $strAddOn),
1807 4
            $this->encoding
1808
        );
1809
    }
1810
1811
    /**
1812
     * A multibyte string shuffle function. It returns a string with its
1813
     * characters in random order.
1814
     *
1815
     * @return static
1816
     *                <p>Object with a shuffled $str.</p>
1817
     */
1818 6
    public function shuffle(): self
1819
    {
1820 6
        return static::create($this->utf8::str_shuffle($this->str), $this->encoding);
1821
    }
1822
1823
    /**
1824
     * Returns the substring beginning at $start, and up to, but not including
1825
     * the index specified by $end. If $end is omitted, the function extracts
1826
     * the remaining string. If $end is negative, it is computed from the end
1827
     * of the string.
1828
     *
1829
     * @param int $start <p>Initial index from which to begin extraction.</p>
1830
     * @param int $end   [optional] <p>Index at which to end extraction. Default: null</p>
1831
     *
1832
     * @return static
1833
     *                <p>Object with its $str being the extracted substring.</p>
1834
     */
1835 34
    public function slice(int $start, int $end = null): self
1836
    {
1837 34
        return static::create(
1838 34
            $this->utf8::str_slice($this->str, $start, $end, $this->encoding),
1839 34
            $this->encoding
1840
        );
1841
    }
1842
1843
    /**
1844
     * Converts the string into an URL slug. This includes replacing non-ASCII
1845
     * characters with their closest ASCII equivalents, removing remaining
1846
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
1847
     * $replacement. The replacement defaults to a single dash, and the string
1848
     * is also converted to lowercase. The language of the source string can
1849
     * also be supplied for language-specific transliteration.
1850
     *
1851
     * @param string $replacement The string used to replace whitespace
1852
     * @param string $language    Language of the source string
1853
     *
1854
     * @return static Object whose $str has been converted to an URL slug
1855
     */
1856 16
    public function slugify(string $replacement = '-', string $language = 'en'): self
1857
    {
1858 16
        $stringy = self::create($this->str);
1859
1860 16
        $langSpecific = self::langSpecificCharsArray($language);
1861 16
        if (!empty($langSpecific)) {
1862
            $stringy->str = \str_replace($langSpecific[0], $langSpecific[1], $stringy->str);
1863
        }
1864
1865 16
        foreach ($this->charsArray() as $key => $value) {
1866 16
            $stringy->str = \str_replace($value, $key, $stringy->str);
1867
        }
1868 16
        $stringy->str = \str_replace('@', $replacement, $stringy->str);
1869
1870 16
        $stringy->str = (string) \preg_replace(
1871 16
            '/[^a-zA-Z\d\s\-_' . \preg_quote($replacement, '/') . ']/u',
1872 16
            '',
1873 16
            $stringy->str
1874
        );
1875 16
        $stringy->str = (string) \preg_replace("/^['\s']+|['\s']+\$/", '', \strtolower($stringy->str));
1876 16
        $stringy->str = (string) \preg_replace('/\B([A-Z])/', '/-\1/', $stringy->str);
1877 16
        $stringy->str = (string) \preg_replace('/[-_\s]+/', $replacement, $stringy->str);
1878
1879 16
        $l = \strlen($replacement);
1880 16 View Code Duplication
        if (\strpos($stringy->str, $replacement) === 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1881 1
            $stringy->str = (string) \substr($stringy->str, $l);
1882
        }
1883
1884 16 View Code Duplication
        if (\substr($stringy->str, -$l) === $replacement) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1885 1
            $stringy->str = (string) \substr($stringy->str, 0, \strlen($stringy->str) - $l);
1886
        }
1887
1888 16
        return static::create($stringy->str, $this->encoding);
1889
    }
1890
1891
    /**
1892
     * Converts the string into an URL slug. This includes replacing non-ASCII
1893
     * characters with their closest ASCII equivalents, removing remaining
1894
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
1895
     * $replacement. The replacement defaults to a single dash, and the string
1896
     * is also converted to lowercase.
1897
     *
1898
     * @param string $replacement [optional] <p>The string used to replace whitespace. Default: '-'</p>
1899
     * @param string $language    [optional] <p>The language for the url. Default: 'de'</p>
1900
     * @param bool   $strToLower  [optional] <p>string to lower. Default: true</p>
1901
     *
1902
     * @return static
1903
     *                <p>Object whose $str has been converted to an URL slug.</p>
1904
     */
1905 15
    public function urlify(string $replacement = '-', string $language = 'de', bool $strToLower = true): self
1906
    {
1907 15
        return static::create(
1908 15
            URLify::slug($this->str, $language, $replacement, $strToLower),
1909 15
            $this->encoding
1910
        );
1911
    }
1912
1913
    /**
1914
     * Convert a string to e.g.: "snake_case"
1915
     *
1916
     * @return static
1917
     *                <p>Object with $str in snake_case.</p>
1918
     */
1919 20
    public function snakeize(): self
1920
    {
1921 20
        return static::create(
1922 20
            $this->utf8::str_snakeize($this->str, $this->encoding),
1923 20
            $this->encoding
1924
        );
1925
    }
1926
1927
    /**
1928
     * Splits the string with the provided regular expression, returning an
1929
     * array of Stringy objects. An optional integer $limit will truncate the
1930
     * results.
1931
     *
1932
     * @param string $pattern <p>The regex with which to split the string.</p>
1933
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no limit</p>
1934
     *
1935
     * @return static[]
1936
     *                  <p>An array of Stringy objects.</p>
1937
     */
1938 35
    public function split(string $pattern, int $limit = null): array
1939
    {
1940 35
        if ($limit === null) {
1941 7
            $limit = -1;
1942
        }
1943
1944 35
        $array = $this->utf8::str_split_pattern($this->str, $pattern, $limit);
1945 35
        foreach ($array as $i => &$value) {
1946 31
            $value = static::create($value, $this->encoding);
1947
        }
1948
1949 35
        return $array;
1950
    }
1951
1952
    /**
1953
     * Returns true if the string begins with $substring, false otherwise. By
1954
     * default, the comparison is case-sensitive, but can be made insensitive
1955
     * by setting $caseSensitive to false.
1956
     *
1957
     * @param string $substring     <p>The substring to look for.</p>
1958
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1959
     *
1960
     * @return bool
1961
     *              <p>Whether or not $str starts with $substring.</p>
1962
     */
1963 22
    public function startsWith(string $substring, bool $caseSensitive = true): bool
1964
    {
1965 22
        if ($caseSensitive) {
1966 14
            return $this->utf8::str_starts_with($this->str, $substring);
1967
        }
1968
1969 8
        return $this->utf8::str_istarts_with($this->str, $substring);
1970
    }
1971
1972
    /**
1973
     * Returns true if the string begins with any of $substrings, false otherwise.
1974
     * By default the comparison is case-sensitive, but can be made insensitive by
1975
     * setting $caseSensitive to false.
1976
     *
1977
     * @param array $substrings    <p>Substrings to look for.</p>
1978
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1979
     *
1980
     * @return bool
1981
     *              <p>Whether or not $str starts with $substring.</p>
1982
     */
1983 23
    public function startsWithAny(array $substrings, bool $caseSensitive = true): bool
1984
    {
1985 23
        if ($caseSensitive) {
1986 15
            return $this->utf8::str_starts_with_any($this->str, $substrings);
1987
        }
1988
1989 8
        return $this->utf8::str_istarts_with_any($this->str, $substrings);
1990
    }
1991
1992
    /**
1993
     * Strip all whitespace characters. This includes tabs and newline characters,
1994
     * as well as multibyte whitespace such as the thin space and ideographic space.
1995
     *
1996
     * @return static
1997
     */
1998 24
    public function stripWhitespace(): self
1999
    {
2000 24
        return static::create(
2001 24
            $this->utf8::strip_whitespace($this->str),
2002 24
            $this->encoding
2003
        );
2004
    }
2005
2006
    /**
2007
     * Remove css media-queries.
2008
     *
2009
     * @return static
2010
     */
2011 1
    public function stripeCssMediaQueries(): self
2012
    {
2013 1
        return static::create(
2014 1
            $this->utf8::css_stripe_media_queries($this->str),
2015 1
            $this->encoding
2016
        );
2017
    }
2018
2019
    /**
2020
     * Remove empty html-tag.
2021
     *
2022
     * e.g.: <tag></tag>
2023
     *
2024
     * @return static
2025
     */
2026 1
    public function stripeEmptyHtmlTags(): self
2027
    {
2028 1
        return static::create(
2029 1
            $this->utf8::html_stripe_empty_tags($this->str),
2030 1
            $this->encoding
2031
        );
2032
    }
2033
2034
    /**
2035
     * Returns the substring beginning at $start with the specified $length.
2036
     * It differs from the $this->utf8::substr() function in that providing a $length of
2037
     * null will return the rest of the string, rather than an empty string.
2038
     *
2039
     * @param int $start  <p>Position of the first character to use.</p>
2040
     * @param int $length [optional] <p>Maximum number of characters used. Default: null</p>
2041
     *
2042
     * @return static
2043
     *                <p>Object with its $str being the substring.</p>
2044
     */
2045 18
    public function substr(int $start, int $length = null): self
2046
    {
2047 18
        return static::create(
2048 18
            $this->utf8::substr(
2049 18
                $this->str,
2050 18
                $start,
2051 18
                $length,
2052 18
                $this->encoding
2053
            ),
2054 18
            $this->encoding
2055
        );
2056
    }
2057
2058
    /**
2059
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
2060
     * If no match is found returns new empty Stringy object.
2061
     *
2062
     * @param string $needle       <p>The string to look for.</p>
2063
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2064
     *
2065
     * @return static
2066
     */
2067 2 View Code Duplication
    public function substringOf(string $needle, bool $beforeNeedle = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2068
    {
2069 2
        return static::create(
2070 2
            $this->utf8::str_substr_first($this->str, $needle, $beforeNeedle, $this->encoding),
2071 2
            $this->encoding
2072
        );
2073
    }
2074
2075
    /**
2076
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
2077
     * If no match is found returns new empty Stringy object.
2078
     *
2079
     * @param string $needle       <p>The string to look for.</p>
2080
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2081
     *
2082
     * @return static
2083
     */
2084 2 View Code Duplication
    public function substringOfIgnoreCase(string $needle, bool $beforeNeedle = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2085
    {
2086 2
        return static::create(
2087 2
            $this->utf8::str_isubstr_first($this->str, $needle, $beforeNeedle, $this->encoding),
2088 2
            $this->encoding
2089
        );
2090
    }
2091
2092
    /**
2093
     * Surrounds $str with the given substring.
2094
     *
2095
     * @param string $substring <p>The substring to add to both sides.</P>
2096
     *
2097
     * @return static
2098
     *                <p>Object whose $str had the substring both prepended and appended.</p>
2099
     */
2100 10
    public function surround(string $substring): self
2101
    {
2102 10
        return static::create(
2103 10
            $substring . $this->str . $substring,
2104 10
            $this->encoding
2105
        );
2106
    }
2107
2108
    /**
2109
     * Returns a case swapped version of the string.
2110
     *
2111
     * @return static
2112
     *                <p>Object whose $str has each character's case swapped.</P>
2113
     */
2114 10
    public function swapCase(): self
2115
    {
2116 10
        return static::create(
2117 10
            $this->utf8::swapCase($this->str, $this->encoding),
2118 10
            $this->encoding
2119
        );
2120
    }
2121
2122
    /**
2123
     * Returns a string with smart quotes, ellipsis characters, and dashes from
2124
     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
2125
     * equivalents.
2126
     *
2127
     * @return static
2128
     *                <p>Object whose $str has those characters removed.</p>
2129
     */
2130 8
    public function tidy(): self
2131
    {
2132 8
        return static::create(
2133 8
            $this->utf8::normalize_msword($this->str),
2134 8
            $this->encoding
2135
        );
2136
    }
2137
2138
    /**
2139
     * Returns a trimmed string with the first letter of each word capitalized.
2140
     * Also accepts an array, $ignore, allowing you to list words not to be
2141
     * capitalized.
2142
     *
2143
     * @param array|string[]|null $ignore [optional] <p>An array of words not to capitalize or null. Default: null</p>
2144
     *
2145
     * @return static
2146
     *                <p>Object with a titleized $str.</p>
2147
     */
2148 10
    public function titleize(array $ignore = null): self
2149
    {
2150 10
        return static::create(
2151 10
            $this->utf8::str_titleize($this->str, $ignore, $this->encoding),
2152 10
            $this->encoding
2153
        );
2154
    }
2155
2156
    /**
2157
     * Returns a trimmed string in proper title case.
2158
     *
2159
     * Also accepts an array, $ignore, allowing you to list words not to be
2160
     * capitalized.
2161
     *
2162
     * Adapted from John Gruber's script.
2163
     *
2164
     * @see https://gist.github.com/gruber/9f9e8650d68b13ce4d78
2165
     *
2166
     * @param array $ignore <p>An array of words not to capitalize.</p>
2167
     *
2168
     * @return static
2169
     *                <p>Object with a titleized $str</p>
2170
     */
2171 35
    public function titleizeForHumans(array $ignore = []): self
2172
    {
2173 35
        return static::create(
2174 35
            $this->utf8::str_titleize_for_humans($this->str, $ignore, $this->encoding),
2175 35
            $this->encoding
2176
        );
2177
    }
2178
2179
    /**
2180
     * Returns an ASCII version of the string. A set of non-ASCII characters are
2181
     * replaced with their closest ASCII counterparts, and the rest are removed
2182
     * unless instructed otherwise.
2183
     *
2184
     * @param bool $strict [optional] <p>Use "transliterator_transliterate()" from PHP-Intl | WARNING: bad performance |
2185
     *                     Default: false</p>
2186
     *
2187
     * @return static
2188
     *                <p>Object whose $str contains only ASCII characters.</p>
2189
     */
2190 16
    public function toTransliterate(bool $strict = false): self
2191
    {
2192 16
        return static::create(
2193 16
            $this->utf8::to_ascii($this->str, '?', $strict),
2194 16
            $this->encoding
2195
        );
2196
    }
2197
2198
    /**
2199
     * Returns an ASCII version of the string. A set of non-ASCII characters are
2200
     * replaced with their closest ASCII counterparts, and the rest are removed
2201
     * by default. The language or locale of the source string can be supplied
2202
     * for language-specific transliteration in any of the following formats:
2203
     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
2204
     * to "aeoeue" rather than "aou" as in other languages.
2205
     *
2206
     * @param string $language          Language of the source string
2207
     * @param bool   $removeUnsupported Whether or not to remove the
2208
     *                                  unsupported characters
2209
     *
2210
     * @return static
2211
     *                <p>Object whose $str contains only ASCII characters.</p>
2212
     */
2213 21
    public function toAscii(string $language = 'en', bool $removeUnsupported = true)
2214
    {
2215
        // init
2216 21
        $str = $this->str;
2217
2218 21
        $langSpecific = self::langSpecificCharsArray($language);
2219 21
        if (!empty($langSpecific)) {
2220 2
            $str = \str_replace($langSpecific[0], $langSpecific[1], $str);
2221
        }
2222
2223 21
        foreach ($this->charsArray() as $key => $value) {
2224 21
            $str = \str_replace($value, $key, $str);
2225
        }
2226
2227 21
        if ($removeUnsupported) {
2228 20
            $str = \preg_replace('/[^\x20-\x7E]/u', '', $str);
2229
        }
2230
2231 21
        return static::create($str, $this->encoding);
2232
    }
2233
2234
    /**
2235
     * Returns a boolean representation of the given logical string value.
2236
     * For example, 'true', '1', 'on' and 'yes' will return true. 'false', '0',
2237
     * 'off', and 'no' will return false. In all instances, case is ignored.
2238
     * For other numeric strings, their sign will determine the return value.
2239
     * In addition, blank strings consisting of only whitespace will return
2240
     * false. For all other strings, the return value is a result of a
2241
     * boolean cast.
2242
     *
2243
     * @return bool
2244
     *              <p>A boolean value for the string.</p>
2245
     */
2246 30
    public function toBoolean(): bool
2247
    {
2248 30
        return $this->utf8::to_boolean($this->str);
2249
    }
2250
2251
    /**
2252
     * Converts all characters in the string to lowercase.
2253
     *
2254
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
2255
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
2256
     *
2257
     * @return static
2258
     *                <p>Object with all characters of $str being lowercase.</p>
2259
     */
2260 12 View Code Duplication
    public function toLowerCase($tryToKeepStringLength = false, $lang = null): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2261
    {
2262 12
        return static::create(
2263 12
            $this->utf8::strtolower(
2264 12
                $this->str,
2265 12
                $this->encoding,
2266 12
                false,
2267 12
                $lang,
2268 12
                $tryToKeepStringLength
2269
            ),
2270 12
            $this->encoding
2271
        );
2272
    }
2273
2274
    /**
2275
     * Converts each tab in the string to some number of spaces, as defined by
2276
     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
2277
     *
2278
     * @param int $tabLength [optional] <p>Number of spaces to replace each tab with. Default: 4</p>
2279
     *
2280
     * @return static
2281
     *                <p>Object whose $str has had tabs switched to spaces.</p>
2282
     */
2283 12 View Code Duplication
    public function toSpaces(int $tabLength = 4): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2284
    {
2285 12
        if ($tabLength === 4) {
2286 6
            $tab = '    ';
2287 6
        } elseif ($tabLength === 2) {
2288 2
            $tab = '  ';
2289
        } else {
2290 4
            $tab = \str_repeat(' ', $tabLength);
2291
        }
2292
2293 12
        return static::create(
2294 12
            \str_replace("\t", $tab, $this->str),
2295 12
            $this->encoding
2296
        );
2297
    }
2298
2299
    /**
2300
     * Return Stringy object as string, but you can also use (string) for automatically casting the object into a
2301
     * string.
2302
     *
2303
     * @return string
2304
     */
2305 1071
    public function toString(): string
2306
    {
2307 1071
        return (string) $this->str;
2308
    }
2309
2310
    /**
2311
     * Converts each occurrence of some consecutive number of spaces, as
2312
     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
2313
     * are converted to a tab.
2314
     *
2315
     * @param int $tabLength [optional] <p>Number of spaces to replace with a tab. Default: 4</p>
2316
     *
2317
     * @return static
2318
     *                <p>Object whose $str has had spaces switched to tabs.</p>
2319
     */
2320 10 View Code Duplication
    public function toTabs(int $tabLength = 4): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2321
    {
2322 10
        if ($tabLength === 4) {
2323 6
            $tab = '    ';
2324 4
        } elseif ($tabLength === 2) {
2325 2
            $tab = '  ';
2326
        } else {
2327 2
            $tab = \str_repeat(' ', $tabLength);
2328
        }
2329
2330 10
        return static::create(
2331 10
            \str_replace($tab, "\t", $this->str),
2332 10
            $this->encoding
2333
        );
2334
    }
2335
2336
    /**
2337
     * Converts the first character of each word in the string to uppercase
2338
     * and all other chars to lowercase.
2339
     *
2340
     * @return static
2341
     *                <p>Object with all characters of $str being title-cased.</p>
2342
     */
2343 10
    public function toTitleCase(): self
2344
    {
2345 10
        return static::create(
2346 10
            $this->utf8::titlecase($this->str, $this->encoding),
2347 10
            $this->encoding
2348
        );
2349
    }
2350
2351
    /**
2352
     * Converts all characters in the string to uppercase.
2353
     *
2354
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
2355
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
2356
     *
2357
     * @return static
2358
     *                <p>Object with all characters of $str being uppercase.</p>
2359
     */
2360 10 View Code Duplication
    public function toUpperCase($tryToKeepStringLength = false, $lang = null): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2361
    {
2362 10
        return static::create(
2363 10
            $this->utf8::strtoupper($this->str, $this->encoding, false, $lang, $tryToKeepStringLength),
2364 10
            $this->encoding
2365
        );
2366
    }
2367
2368
    /**
2369
     * Returns a string with whitespace removed from the start and end of the
2370
     * string. Supports the removal of unicode whitespace. Accepts an optional
2371
     * string of characters to strip instead of the defaults.
2372
     *
2373
     * @param string $chars [optional] <p>String of characters to strip. Default: null</p>
2374
     *
2375
     * @return static
2376
     *                <p>Object with a trimmed $str.</p>
2377
     */
2378 24
    public function trim(string $chars = null): self
2379
    {
2380 24
        return static::create(
2381 24
            $this->utf8::trim($this->str, $chars),
2382 24
            $this->encoding
2383
        );
2384
    }
2385
2386
    /**
2387
     * Returns a string with whitespace removed from the start of the string.
2388
     * Supports the removal of unicode whitespace. Accepts an optional
2389
     * string of characters to strip instead of the defaults.
2390
     *
2391
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
2392
     *
2393
     * @return static
2394
     *                <p>Object with a trimmed $str.</p>
2395
     */
2396 26
    public function trimLeft(string $chars = null): self
2397
    {
2398 26
        return static::create(
2399 26
            $this->utf8::ltrim($this->str, $chars),
2400 26
            $this->encoding
2401
        );
2402
    }
2403
2404
    /**
2405
     * Returns a string with whitespace removed from the end of the string.
2406
     * Supports the removal of unicode whitespace. Accepts an optional
2407
     * string of characters to strip instead of the defaults.
2408
     *
2409
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
2410
     *
2411
     * @return static
2412
     *                <p>Object with a trimmed $str.</p>
2413
     */
2414 26
    public function trimRight(string $chars = null): self
2415
    {
2416 26
        return static::create(
2417 26
            $this->utf8::rtrim($this->str, $chars),
2418 26
            $this->encoding
2419
        );
2420
    }
2421
2422
    /**
2423
     * Truncates the string to a given length. If $substring is provided, and
2424
     * truncating occurs, the string is further truncated so that the substring
2425
     * may be appended without exceeding the desired length.
2426
     *
2427
     * @param int    $length    <p>Desired length of the truncated string.</p>
2428
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
2429
     *
2430
     * @return static
2431
     *                <p>Object with the resulting $str after truncating.</p>
2432
     */
2433 44
    public function truncate(int $length, string $substring = ''): self
2434
    {
2435 44
        return static::create(
2436 44
            $this->utf8::str_truncate($this->str, $length, $substring, $this->encoding),
2437 44
            $this->encoding
2438
        );
2439
    }
2440
2441
    /**
2442
     * Returns a lowercase and trimmed string separated by underscores.
2443
     * Underscores are inserted before uppercase characters (with the exception
2444
     * of the first character of the string), and in place of spaces as well as
2445
     * dashes.
2446
     *
2447
     * @return static
2448
     *                <p>Object with an underscored $str.</p>
2449
     */
2450 32
    public function underscored(): self
2451
    {
2452 32
        return $this->delimit('_');
2453
    }
2454
2455
    /**
2456
     * Returns an UpperCamelCase version of the supplied string. It trims
2457
     * surrounding spaces, capitalizes letters following digits, spaces, dashes
2458
     * and underscores, and removes spaces, dashes, underscores.
2459
     *
2460
     * @return static
2461
     *                <p>Object with $str in UpperCamelCase.</p>
2462
     */
2463 26
    public function upperCamelize(): self
2464
    {
2465 26
        return static::create(
2466 26
            $this->utf8::str_upper_camelize($this->str, $this->encoding),
2467 26
            $this->encoding
2468
        );
2469
    }
2470
2471
    /**
2472
     * Converts the first character of the supplied string to upper case.
2473
     *
2474
     * @return static
2475
     *                <p>Object with the first character of $str being upper case.</p>
2476
     */
2477 12
    public function upperCaseFirst(): self
2478
    {
2479 12
        return static::create($this->utf8::ucfirst($this->str, $this->encoding), $this->encoding);
2480
    }
2481
2482
    /**
2483
     * Converts the string into an valid UTF-8 string.
2484
     *
2485
     * @return static
2486
     */
2487 1
    public function utf8ify(): self
2488
    {
2489 1
        return static::create($this->utf8::cleanup($this->str), $this->encoding);
2490
    }
2491
2492
    /**
2493
     * Returns the replacements for the toAscii() method.
2494
     *
2495
     * @return array
2496
     *               <p>An array of replacements.</p>
2497
     */
2498 37
    protected function charsArray(): array
2499
    {
2500 37
        static $charsArray;
2501
2502 37
        if (isset($charsArray)) {
2503 36
            return $charsArray;
2504
        }
2505
2506
        return $charsArray = [
2507 1
            '0' => ['°', '₀', '۰', '0'],
2508
            '1' => ['¹', '₁', '۱', '1'],
2509
            '2' => ['²', '₂', '۲', '2'],
2510
            '3' => ['³', '₃', '۳', '3'],
2511
            '4' => ['⁴', '₄', '۴', '٤', '4'],
2512
            '5' => ['⁵', '₅', '۵', '٥', '5'],
2513
            '6' => ['⁶', '₆', '۶', '٦', '6'],
2514
            '7' => ['⁷', '₇', '۷', '7'],
2515
            '8' => ['⁸', '₈', '۸', '8'],
2516
            '9' => ['⁹', '₉', '۹', '9'],
2517
            'a' => [
2518
                'à',
2519
                'á',
2520
                'ả',
2521
                'ã',
2522
                'ạ',
2523
                'ă',
2524
                'ắ',
2525
                'ằ',
2526
                'ẳ',
2527
                'ẵ',
2528
                'ặ',
2529
                'â',
2530
                'ấ',
2531
                'ầ',
2532
                'ẩ',
2533
                'ẫ',
2534
                'ậ',
2535
                'ā',
2536
                'ą',
2537
                'å',
2538
                'α',
2539
                'ά',
2540
                'ἀ',
2541
                'ἁ',
2542
                'ἂ',
2543
                'ἃ',
2544
                'ἄ',
2545
                'ἅ',
2546
                'ἆ',
2547
                'ἇ',
2548
                'ᾀ',
2549
                'ᾁ',
2550
                'ᾂ',
2551
                'ᾃ',
2552
                'ᾄ',
2553
                'ᾅ',
2554
                'ᾆ',
2555
                'ᾇ',
2556
                'ὰ',
2557
                'ά',
2558
                'ᾰ',
2559
                'ᾱ',
2560
                'ᾲ',
2561
                'ᾳ',
2562
                'ᾴ',
2563
                'ᾶ',
2564
                'ᾷ',
2565
                'а',
2566
                'أ',
2567
                'အ',
2568
                'ာ',
2569
                'ါ',
2570
                'ǻ',
2571
                'ǎ',
2572
                'ª',
2573
                'ა',
2574
                'अ',
2575
                'ا',
2576
                'a',
2577
                'ä',
2578
            ],
2579
            'b' => ['б', 'β', 'ب', 'ဗ', 'ბ', 'b'],
2580
            'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ', 'c'],
2581
            'd' => [
2582
                'ď',
2583
                'ð',
2584
                'đ',
2585
                'ƌ',
2586
                'ȡ',
2587
                'ɖ',
2588
                'ɗ',
2589
                'ᵭ',
2590
                'ᶁ',
2591
                'ᶑ',
2592
                'д',
2593
                'δ',
2594
                'د',
2595
                'ض',
2596
                'ဍ',
2597
                'ဒ',
2598
                'დ',
2599
                'd',
2600
            ],
2601
            'e' => [
2602
                'é',
2603
                'è',
2604
                'ẻ',
2605
                'ẽ',
2606
                'ẹ',
2607
                'ê',
2608
                'ế',
2609
                'ề',
2610
                'ể',
2611
                'ễ',
2612
                'ệ',
2613
                'ë',
2614
                'ē',
2615
                'ę',
2616
                'ě',
2617
                'ĕ',
2618
                'ė',
2619
                'ε',
2620
                'έ',
2621
                'ἐ',
2622
                'ἑ',
2623
                'ἒ',
2624
                'ἓ',
2625
                'ἔ',
2626
                'ἕ',
2627
                'ὲ',
2628
                'έ',
2629
                'е',
2630
                'ё',
2631
                'э',
2632
                'є',
2633
                'ə',
2634
                'ဧ',
2635
                'ေ',
2636
                'ဲ',
2637
                'ე',
2638
                'ए',
2639
                'إ',
2640
                'ئ',
2641
                'e',
2642
            ],
2643
            'f' => ['ф', 'φ', 'ف', 'ƒ', 'ფ', 'f'],
2644
            'g' => [
2645
                'ĝ',
2646
                'ğ',
2647
                'ġ',
2648
                'ģ',
2649
                'г',
2650
                'ґ',
2651
                'γ',
2652
                'ဂ',
2653
                'გ',
2654
                'گ',
2655
                'g',
2656
            ],
2657
            'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ', 'h'],
2658
            'i' => [
2659
                'í',
2660
                'ì',
2661
                'ỉ',
2662
                'ĩ',
2663
                'ị',
2664
                'î',
2665
                'ï',
2666
                'ī',
2667
                'ĭ',
2668
                'į',
2669
                'ı',
2670
                'ι',
2671
                'ί',
2672
                'ϊ',
2673
                'ΐ',
2674
                'ἰ',
2675
                'ἱ',
2676
                'ἲ',
2677
                'ἳ',
2678
                'ἴ',
2679
                'ἵ',
2680
                'ἶ',
2681
                'ἷ',
2682
                'ὶ',
2683
                'ί',
2684
                'ῐ',
2685
                'ῑ',
2686
                'ῒ',
2687
                'ΐ',
2688
                'ῖ',
2689
                'ῗ',
2690
                'і',
2691
                'ї',
2692
                'и',
2693
                'ဣ',
2694
                'ိ',
2695
                'ီ',
2696
                'ည်',
2697
                'ǐ',
2698
                'ი',
2699
                'इ',
2700
                'ی',
2701
                'i',
2702
            ],
2703
            'j' => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج', 'j'],
2704
            'k' => [
2705
                'ķ',
2706
                'ĸ',
2707
                'к',
2708
                'κ',
2709
                'Ķ',
2710
                'ق',
2711
                'ك',
2712
                'က',
2713
                'კ',
2714
                'ქ',
2715
                'ک',
2716
                'k',
2717
            ],
2718
            'l' => [
2719
                'ł',
2720
                'ľ',
2721
                'ĺ',
2722
                'ļ',
2723
                'ŀ',
2724
                'л',
2725
                'λ',
2726
                'ل',
2727
                'လ',
2728
                'ლ',
2729
                'l',
2730
            ],
2731
            'm' => ['м', 'μ', 'م', 'မ', 'მ', 'm'],
2732
            'n' => [
2733
                'ñ',
2734
                'ń',
2735
                'ň',
2736
                'ņ',
2737
                'ʼn',
2738
                'ŋ',
2739
                'ν',
2740
                'н',
2741
                'ن',
2742
                'န',
2743
                'ნ',
2744
                'n',
2745
            ],
2746
            'o' => [
2747
                'ó',
2748
                'ò',
2749
                'ỏ',
2750
                'õ',
2751
                'ọ',
2752
                'ô',
2753
                'ố',
2754
                'ồ',
2755
                'ổ',
2756
                'ỗ',
2757
                'ộ',
2758
                'ơ',
2759
                'ớ',
2760
                'ờ',
2761
                'ở',
2762
                'ỡ',
2763
                'ợ',
2764
                'ø',
2765
                'ō',
2766
                'ő',
2767
                'ŏ',
2768
                'ο',
2769
                'ὀ',
2770
                'ὁ',
2771
                'ὂ',
2772
                'ὃ',
2773
                'ὄ',
2774
                'ὅ',
2775
                'ὸ',
2776
                'ό',
2777
                'о',
2778
                'و',
2779
                'θ',
2780
                'ို',
2781
                'ǒ',
2782
                'ǿ',
2783
                'º',
2784
                'ო',
2785
                'ओ',
2786
                'o',
2787
                'ö',
2788
            ],
2789
            'p' => ['п', 'π', 'ပ', 'პ', 'پ', 'p'],
2790
            'q' => ['ყ', 'q'],
2791
            'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ', 'r'],
2792
            's' => [
2793
                'ś',
2794
                'š',
2795
                'ş',
2796
                'с',
2797
                'σ',
2798
                'ș',
2799
                'ς',
2800
                'س',
2801
                'ص',
2802
                'စ',
2803
                'ſ',
2804
                'ს',
2805
                's',
2806
            ],
2807
            't' => [
2808
                'ť',
2809
                'ţ',
2810
                'т',
2811
                'τ',
2812
                'ț',
2813
                'ت',
2814
                'ط',
2815
                'ဋ',
2816
                'တ',
2817
                'ŧ',
2818
                'თ',
2819
                'ტ',
2820
                't',
2821
            ],
2822
            'u' => [
2823
                'ú',
2824
                'ù',
2825
                'ủ',
2826
                'ũ',
2827
                'ụ',
2828
                'ư',
2829
                'ứ',
2830
                'ừ',
2831
                'ử',
2832
                'ữ',
2833
                'ự',
2834
                'û',
2835
                'ū',
2836
                'ů',
2837
                'ű',
2838
                'ŭ',
2839
                'ų',
2840
                'µ',
2841
                'у',
2842
                'ဉ',
2843
                'ု',
2844
                'ူ',
2845
                'ǔ',
2846
                'ǖ',
2847
                'ǘ',
2848
                'ǚ',
2849
                'ǜ',
2850
                'უ',
2851
                'उ',
2852
                'u',
2853
                'ў',
2854
                'ü',
2855
            ],
2856
            'v' => ['в', 'ვ', 'ϐ', 'v'],
2857
            'w' => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ', 'w'],
2858
            'x' => ['χ', 'ξ', 'x'],
2859
            'y' => [
2860
                'ý',
2861
                'ỳ',
2862
                'ỷ',
2863
                'ỹ',
2864
                'ỵ',
2865
                'ÿ',
2866
                'ŷ',
2867
                'й',
2868
                'ы',
2869
                'υ',
2870
                'ϋ',
2871
                'ύ',
2872
                'ΰ',
2873
                'ي',
2874
                'ယ',
2875
                'y',
2876
            ],
2877
            'z'    => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ', 'z'],
2878
            'aa'   => ['ع', 'आ', 'آ'],
2879
            'ae'   => ['æ', 'ǽ'],
2880
            'ai'   => ['ऐ'],
2881
            'ch'   => ['ч', 'ჩ', 'ჭ', 'چ'],
2882
            'dj'   => ['ђ', 'đ'],
2883
            'dz'   => ['џ', 'ძ'],
2884
            'ei'   => ['ऍ'],
2885
            'gh'   => ['غ', 'ღ'],
2886
            'ii'   => ['ई'],
2887
            'ij'   => ['ij'],
2888
            'kh'   => ['х', 'خ', 'ხ'],
2889
            'lj'   => ['љ'],
2890
            'nj'   => ['њ'],
2891
            'oe'   => ['œ', 'ؤ'],
2892
            'oi'   => ['ऑ'],
2893
            'oii'  => ['ऒ'],
2894
            'ps'   => ['ψ'],
2895
            'sh'   => ['ш', 'შ', 'ش'],
2896
            'shch' => ['щ'],
2897
            'ss'   => ['ß'],
2898
            'sx'   => ['ŝ'],
2899
            'th'   => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'],
2900
            'ts'   => ['ц', 'ც', 'წ'],
2901
            'uu'   => ['ऊ'],
2902
            'ya'   => ['я'],
2903
            'yu'   => ['ю'],
2904
            'zh'   => ['ж', 'ჟ', 'ژ'],
2905
            '(c)'  => ['©'],
2906
            'A'    => [
2907
                'Á',
2908
                'À',
2909
                'Ả',
2910
                'Ã',
2911
                'Ạ',
2912
                'Ă',
2913
                'Ắ',
2914
                'Ằ',
2915
                'Ẳ',
2916
                'Ẵ',
2917
                'Ặ',
2918
                'Â',
2919
                'Ấ',
2920
                'Ầ',
2921
                'Ẩ',
2922
                'Ẫ',
2923
                'Ậ',
2924
                'Å',
2925
                'Ā',
2926
                'Ą',
2927
                'Α',
2928
                'Ά',
2929
                'Ἀ',
2930
                'Ἁ',
2931
                'Ἂ',
2932
                'Ἃ',
2933
                'Ἄ',
2934
                'Ἅ',
2935
                'Ἆ',
2936
                'Ἇ',
2937
                'ᾈ',
2938
                'ᾉ',
2939
                'ᾊ',
2940
                'ᾋ',
2941
                'ᾌ',
2942
                'ᾍ',
2943
                'ᾎ',
2944
                'ᾏ',
2945
                'Ᾰ',
2946
                'Ᾱ',
2947
                'Ὰ',
2948
                'Ά',
2949
                'ᾼ',
2950
                'А',
2951
                'Ǻ',
2952
                'Ǎ',
2953
                'A',
2954
                'Ä',
2955
            ],
2956
            'B' => ['Б', 'Β', 'ब', 'B'],
2957
            'C' => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ', 'C'],
2958
            'D' => [
2959
                'Ď',
2960
                'Ð',
2961
                'Đ',
2962
                'Ɖ',
2963
                'Ɗ',
2964
                'Ƌ',
2965
                'ᴅ',
2966
                'ᴆ',
2967
                'Д',
2968
                'Δ',
2969
                'D',
2970
            ],
2971
            'E' => [
2972
                'É',
2973
                'È',
2974
                'Ẻ',
2975
                'Ẽ',
2976
                'Ẹ',
2977
                'Ê',
2978
                'Ế',
2979
                'Ề',
2980
                'Ể',
2981
                'Ễ',
2982
                'Ệ',
2983
                'Ë',
2984
                'Ē',
2985
                'Ę',
2986
                'Ě',
2987
                'Ĕ',
2988
                'Ė',
2989
                'Ε',
2990
                'Έ',
2991
                'Ἐ',
2992
                'Ἑ',
2993
                'Ἒ',
2994
                'Ἓ',
2995
                'Ἔ',
2996
                'Ἕ',
2997
                'Έ',
2998
                'Ὲ',
2999
                'Е',
3000
                'Ё',
3001
                'Э',
3002
                'Є',
3003
                'Ə',
3004
                'E',
3005
            ],
3006
            'F' => ['Ф', 'Φ', 'F'],
3007
            'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ', 'G'],
3008
            'H' => ['Η', 'Ή', 'Ħ', 'H'],
3009
            'I' => [
3010
                'Í',
3011
                'Ì',
3012
                'Ỉ',
3013
                'Ĩ',
3014
                'Ị',
3015
                'Î',
3016
                'Ï',
3017
                'Ī',
3018
                'Ĭ',
3019
                'Į',
3020
                'İ',
3021
                'Ι',
3022
                'Ί',
3023
                'Ϊ',
3024
                'Ἰ',
3025
                'Ἱ',
3026
                'Ἳ',
3027
                'Ἴ',
3028
                'Ἵ',
3029
                'Ἶ',
3030
                'Ἷ',
3031
                'Ῐ',
3032
                'Ῑ',
3033
                'Ὶ',
3034
                'Ί',
3035
                'И',
3036
                'І',
3037
                'Ї',
3038
                'Ǐ',
3039
                'ϒ',
3040
                'I',
3041
            ],
3042
            'J' => ['J'],
3043
            'K' => ['К', 'Κ', 'K'],
3044
            'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल', 'L'],
3045
            'M' => ['М', 'Μ', 'M'],
3046
            'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν', 'N'],
3047
            'O' => [
3048
                'Ó',
3049
                'Ò',
3050
                'Ỏ',
3051
                'Õ',
3052
                'Ọ',
3053
                'Ô',
3054
                'Ố',
3055
                'Ồ',
3056
                'Ổ',
3057
                'Ỗ',
3058
                'Ộ',
3059
                'Ơ',
3060
                'Ớ',
3061
                'Ờ',
3062
                'Ở',
3063
                'Ỡ',
3064
                'Ợ',
3065
                'Ø',
3066
                'Ō',
3067
                'Ő',
3068
                'Ŏ',
3069
                'Ο',
3070
                'Ό',
3071
                'Ὀ',
3072
                'Ὁ',
3073
                'Ὂ',
3074
                'Ὃ',
3075
                'Ὄ',
3076
                'Ὅ',
3077
                'Ὸ',
3078
                'Ό',
3079
                'О',
3080
                'Θ',
3081
                'Ө',
3082
                'Ǒ',
3083
                'Ǿ',
3084
                'O',
3085
                'Ö',
3086
            ],
3087
            'P' => ['П', 'Π', 'P'],
3088
            'Q' => ['Q'],
3089
            'R' => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ', 'R'],
3090
            'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ', 'S'],
3091
            'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ', 'T'],
3092
            'U' => [
3093
                'Ú',
3094
                'Ù',
3095
                'Ủ',
3096
                'Ũ',
3097
                'Ụ',
3098
                'Ư',
3099
                'Ứ',
3100
                'Ừ',
3101
                'Ử',
3102
                'Ữ',
3103
                'Ự',
3104
                'Û',
3105
                'Ū',
3106
                'Ů',
3107
                'Ű',
3108
                'Ŭ',
3109
                'Ų',
3110
                'У',
3111
                'Ǔ',
3112
                'Ǖ',
3113
                'Ǘ',
3114
                'Ǚ',
3115
                'Ǜ',
3116
                'U',
3117
                'Ў',
3118
                'Ü',
3119
            ],
3120
            'V' => ['В', 'V'],
3121
            'W' => ['Ω', 'Ώ', 'Ŵ', 'W'],
3122
            'X' => ['Χ', 'Ξ', 'X'],
3123
            'Y' => [
3124
                'Ý',
3125
                'Ỳ',
3126
                'Ỷ',
3127
                'Ỹ',
3128
                'Ỵ',
3129
                'Ÿ',
3130
                'Ῠ',
3131
                'Ῡ',
3132
                'Ὺ',
3133
                'Ύ',
3134
                'Ы',
3135
                'Й',
3136
                'Υ',
3137
                'Ϋ',
3138
                'Ŷ',
3139
                'Y',
3140
            ],
3141
            'Z'    => ['Ź', 'Ž', 'Ż', 'З', 'Ζ', 'Z'],
3142
            'AE'   => ['Æ', 'Ǽ'],
3143
            'Ch'   => ['Ч'],
3144
            'Dj'   => ['Ђ'],
3145
            'Dz'   => ['Џ'],
3146
            'Gx'   => ['Ĝ'],
3147
            'Hx'   => ['Ĥ'],
3148
            'Ij'   => ['IJ'],
3149
            'Jx'   => ['Ĵ'],
3150
            'Kh'   => ['Х'],
3151
            'Lj'   => ['Љ'],
3152
            'Nj'   => ['Њ'],
3153
            'Oe'   => ['Œ'],
3154
            'Ps'   => ['Ψ'],
3155
            'Sh'   => ['Ш'],
3156
            'Shch' => ['Щ'],
3157
            'Ss'   => ['ẞ'],
3158
            'Th'   => ['Þ'],
3159
            'Ts'   => ['Ц'],
3160
            'Ya'   => ['Я'],
3161
            'Yu'   => ['Ю'],
3162
            'Zh'   => ['Ж'],
3163
            ' '    => [
3164
                "\xC2\xA0",
3165
                "\xE2\x80\x80",
3166
                "\xE2\x80\x81",
3167
                "\xE2\x80\x82",
3168
                "\xE2\x80\x83",
3169
                "\xE2\x80\x84",
3170
                "\xE2\x80\x85",
3171
                "\xE2\x80\x86",
3172
                "\xE2\x80\x87",
3173
                "\xE2\x80\x88",
3174
                "\xE2\x80\x89",
3175
                "\xE2\x80\x8A",
3176
                "\xE2\x80\xAF",
3177
                "\xE2\x81\x9F",
3178
                "\xE3\x80\x80",
3179
                "\xEF\xBE\xA0",
3180
            ],
3181
        ];
3182
    }
3183
3184
    /**
3185
     * Returns true if $str matches the supplied pattern, false otherwise.
3186
     *
3187
     * @param string $pattern <p>Regex pattern to match against.</p>
3188
     *
3189
     * @return bool
3190
     *              <p>Whether or not $str matches the pattern.</p>
3191
     */
3192 12
    protected function matchesPattern(string $pattern): bool
3193
    {
3194 12
        return $this->utf8::str_matches_pattern($this->str, $pattern);
3195
    }
3196
3197
    /**
3198
     * Returns language-specific replacements for the toAscii() method.
3199
     * For example, German will map 'ä' to 'ae', while other languages
3200
     * will simply return 'a'.
3201
     *
3202
     * @param string $language Language of the source string
3203
     *
3204
     * @return array an array of replacements
3205
     */
3206 37
    protected static function langSpecificCharsArray(string $language = 'en'): array
3207
    {
3208 37
        $split = \preg_split('/[-_]/', $language);
3209 37
        if ($split === false) {
3210
            return [];
3211
        }
3212
3213 37
        if (!isset($split[0])) {
3214
            return [];
3215
        }
3216
3217 37
        $language = \strtolower($split[0]);
3218 37
        static $charsArray = [];
3219
3220 37
        if (isset($charsArray[$language])) {
3221 35
            return $charsArray[$language];
3222
        }
3223
3224
        $languageSpecific = [
3225 2
            'de' => [
3226
                ['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü'],
3227
                ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'],
3228
            ],
3229
            'bg' => [
3230
                ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'],
3231
                ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'],
3232
            ],
3233
        ];
3234
3235 2
        $charsArray[$language] = $languageSpecific[$language] ?? [];
3236
3237 2
        return $charsArray[$language];
3238
    }
3239
}
3240