Completed
Push — master ( b7c649...522f83 )
by Lars
14:36
created

Stringy::replace()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
nc 4
nop 3
dl 0
loc 22
ccs 6
cts 6
cp 1
crap 6
rs 8.9457
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 2105
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
46
     *
47 2105
     * @throws \InvalidArgumentException <p>if an array or object without a
48 2
     *                                   __toString method is passed as the first argument</p>
49 2
     */
50
    public function __construct($str = '', string $encoding = null)
51
    {
52
        if (\is_array($str)) {
53
            throw new \InvalidArgumentException(
54 2103
                'Passed value cannot be an array'
55
            );
56 2103
        }
57
58 2
        if (
59 2
            \is_object($str)
60
            &&
61
            !\method_exists($str, '__toString')
62
        ) {
63 2101
            throw new \InvalidArgumentException(
64
                'Passed object must have a __toString method'
65 2101
            );
66
        }
67
68 2101
        $this->str = (string) $str;
69
70 2101
        static $UTF8 = null;
71
        if ($UTF8 === null) {
72
            $UTF8 = new UTF8();
73
        }
74
        $this->utf8 = $UTF8;
75
76
        if ($encoding !== 'UTF-8') {
77 978
            $this->encoding = $this->utf8::normalize_encoding($encoding, 'UTF-8');
78
        } else {
79 978
            $this->encoding = $encoding;
80
        }
81
    }
82
83
    /**
84
     * Returns the value in $str.
85
     *
86
     * @return string <p>The current value of the $str property.</p>
87
     */
88
    public function __toString()
89
    {
90 2
        return (string) $this->str;
91
    }
92 2
93 2
    /**
94 2
     * Gets the substring after the first occurrence of a separator.
95 2
     * If no match is found returns new empty Stringy object.
96 2
     *
97
     * @param string $separator
98
     *
99
     * @return static
100
     */
101
    public function afterFirst(string $separator): self
102
    {
103
        return static::create(
104
            $this->utf8::str_substr_after_first_separator(
105
                $this->str,
106
                $separator,
107
                $this->encoding
108
            )
109 1
        );
110
    }
111 1
112 1
    /**
113 1
     * Gets the substring after the first occurrence of a separator.
114 1
     * If no match is found returns new empty Stringy object.
115 1
     *
116
     * @param string $separator
117
     *
118
     * @return static
119
     */
120
    public function afterFirstIgnoreCase(string $separator): self
121
    {
122
        return static::create(
123
            $this->utf8::str_isubstr_after_first_separator(
124
                $this->str,
125
                $separator,
126
                $this->encoding
127
            )
128 1
        );
129
    }
130 1
131 1
    /**
132 1
     * Gets the substring after the last occurrence of a separator.
133 1
     * If no match is found returns new empty Stringy object.
134 1
     *
135
     * @param string $separator
136
     *
137
     * @return static
138
     */
139
    public function afterLast(string $separator): self
140
    {
141
        return static::create(
142
            $this->utf8::str_substr_after_last_separator(
143
                $this->str,
144
                $separator,
145
                $this->encoding
146
            )
147 1
        );
148
    }
149 1
150 1
    /**
151 1
     * Gets the substring after the last occurrence of a separator.
152 1
     * If no match is found returns new empty Stringy object.
153 1
     *
154
     * @param string $separator
155
     *
156
     * @return static
157
     */
158
    public function afterLastIgnoreCase(string $separator): self
159
    {
160
        return static::create(
161
            $this->utf8::str_isubstr_after_last_separator(
162
                $this->str,
163
                $separator,
164
                $this->encoding
165 7
            )
166
        );
167 7
    }
168
169
    /**
170
     * Returns a new string with $string appended.
171
     *
172
     * @param string $string <p>The string to append.</p>
173
     *
174
     * @return static <p>Object with appended $string.</p>
175
     */
176
    public function append(string $string): self
177 1
    {
178
        return static::create($this->str . $string, $this->encoding);
179 1
    }
180
181 1
    /**
182
     * Append an password (limited to chars that are good readable).
183
     *
184
     * @param int $length <p>Length of the random string.</p>
185
     *
186
     * @return static <p>Object with appended password.</p>
187
     */
188
    public function appendPassword(int $length): self
189
    {
190
        return $this->appendRandomString(
191
            $length,
192 2
            '2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ!?_#'
193
        );
194 2
    }
195
196 2
    /**
197
     * Append an random string.
198
     *
199
     * @param int    $length        <p>Length of the random string.</p>
200
     * @param string $possibleChars [optional] <p>Characters string for the random selection.</p>
201
     *
202
     * @return static <p>Object with appended random string.</p>
203
     */
204
    public function appendRandomString(int $length, string $possibleChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'): self
205
    {
206
        $str = $this->utf8::get_random_string($length, $possibleChars);
207 1
208
        return $this->append($str);
209 1
    }
210
211 1
    /**
212
     * Append an unique identifier.
213
     *
214
     * @param int|string $entropyExtra [optional] <p>Extra entropy via a string or int value.</p>
215
     * @param bool       $md5          [optional] <p>Return the unique identifier as md5-hash? Default: true</p>
216
     *
217
     * @return static <p>Object with appended unique identifier as md5-hash.</p>
218
     */
219
    public function appendUniqueIdentifier($entropyExtra = '', bool $md5 = true): self
220
    {
221 16
        return $this->append(
222
            $this->utf8::get_unique_string($entropyExtra, $md5)
223 16
        );
224
    }
225 16
226
    /**
227
     * Returns the character at $index, with indexes starting at 0.
228
     *
229
     * @param int $index <p>Position of the character.</p>
230
     *
231
     * @return static <p>The character at $index.</p>
232
     */
233
    public function at(int $index): self
234
    {
235
        return static::create($this->utf8::char_at($this->str, $index), $this->encoding);
236 1
    }
237
238 1
    /**
239 1
     * Gets the substring before the first occurrence of a separator.
240 1
     * If no match is found returns new empty Stringy object.
241 1
     *
242 1
     * @param string $separator
243
     *
244
     * @return static
245
     */
246
    public function beforeFirst(string $separator): self
247
    {
248
        return static::create(
249
            $this->utf8::str_substr_before_first_separator(
250
                $this->str,
251
                $separator,
252
                $this->encoding
253
            )
254
        );
255 1
    }
256
257 1
    /**
258 1
     * Gets the substring before the first occurrence of a separator.
259 1
     * If no match is found returns new empty Stringy object.
260 1
     *
261 1
     * @param string $separator
262
     *
263
     * @return static
264
     */
265
    public function beforeFirstIgnoreCase(string $separator): self
266
    {
267
        return static::create(
268
            $this->utf8::str_isubstr_before_first_separator(
269
                $this->str,
270
                $separator,
271
                $this->encoding
272
            )
273
        );
274 1
    }
275
276 1
    /**
277 1
     * Gets the substring before the last occurrence of a separator.
278 1
     * If no match is found returns new empty Stringy object.
279 1
     *
280 1
     * @param string $separator
281
     *
282
     * @return static
283
     */
284
    public function beforeLast(string $separator): self
285
    {
286
        return static::create(
287
            $this->utf8::str_substr_before_last_separator(
288
                $this->str,
289
                $separator,
290
                $this->encoding
291
            )
292
        );
293 1
    }
294
295 1
    /**
296 1
     * Gets the substring before the last occurrence of a separator.
297 1
     * If no match is found returns new empty Stringy object.
298 1
     *
299 1
     * @param string $separator
300
     *
301
     * @return static
302
     */
303
    public function beforeLastIgnoreCase(string $separator): self
304
    {
305
        return static::create(
306
            $this->utf8::str_isubstr_before_last_separator(
307
                $this->str,
308
                $separator,
309
                $this->encoding
310
            )
311
        );
312
    }
313
314
    /**
315 32
     * Returns the substring between $start and $end, if found, or an empty
316
     * string. An optional offset may be supplied from which to begin the
317 32
     * search for the start string.
318 32
     *
319 32
     * @param string $start  <p>Delimiter marking the start of the substring.</p>
320 32
     * @param string $end    <p>Delimiter marking the end of the substring.</p>
321 32
     * @param int    $offset [optional] <p>Index from which to begin the search. Default: 0</p>
322 32
     *
323
     * @return static <p>Object whose $str is a substring between $start and $end.</p>
324
     */
325 32
    public function between(string $start, string $end, int $offset = null): self
326
    {
327
        /** @noinspection UnnecessaryCastingInspection */
328
        $str = $this->utf8::between(
329
            $this->str,
330
            $start,
331
            $end,
332
            (int) $offset,
333
            $this->encoding
334
        );
335 38
336
        return static::create($str, $this->encoding);
337 38
    }
338 38
339 38
    /**
340
     * Returns a camelCase version of the string. Trims surrounding spaces,
341
     * capitalizes letters following digits, spaces, dashes and underscores,
342
     * and removes spaces, dashes, as well as underscores.
343
     *
344
     * @return static <p>Object with $str in camelCase.</p>
345
     */
346
    public function camelize(): self
347
    {
348
        return static::create(
349 39
            $this->utf8::str_camelize($this->str, $this->encoding),
350
            $this->encoding
351 39
        );
352 39
    }
353 39
354
    /**
355
     * Returns the string with the first letter of each word capitalized,
356
     * except for when the word is a name which shouldn't be capitalized.
357
     *
358
     * @return static <p>Object with $str capitalized.</p>
359
     */
360
    public function capitalizePersonalName(): self
361
    {
362 8
        return static::create(
363
            $this->utf8::str_capitalize_name($this->str),
364 8
            $this->encoding
365
        );
366
    }
367
368
    /**
369
     * Returns an array consisting of the characters in the string.
370
     *
371
     * @return array <p>An array of string chars.</p>
372
     */
373
    public function chars(): array
374 26
    {
375
        return $this->utf8::str_split($this->str);
376 26
    }
377
378 26
    /**
379
     * Trims the string and replaces consecutive whitespace characters with a
380
     * single space. This includes tabs and newline characters, as well as
381
     * multibyte whitespace such as the thin space and ideographic space.
382
     *
383
     * @return static <p>Object with a trimmed $str and condensed whitespace.</p>
384
     */
385
    public function collapseWhitespace(): self
386
    {
387
        return static::create(
388
            $this->utf8::collapse_whitespace($this->str),
389
            $this->encoding
390
        );
391 42
    }
392
393 42
    /**
394 42
     * Returns true if the string contains $needle, false otherwise. By default
395 42
     * the comparison is case-sensitive, but can be made insensitive by setting
396 42
     * $caseSensitive to false.
397 42
     *
398
     * @param string $needle        <p>Substring to look for.</p>
399
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
400
     *
401
     * @return bool <p>Whether or not $str contains $needle.</p>
402
     */
403
    public function contains(string $needle, bool $caseSensitive = true): bool
404
    {
405
        return $this->utf8::str_contains(
406
            $this->str,
407
            $needle,
408
            $caseSensitive
409
        );
410
    }
411 87
412
    /**
413 87
     * Returns true if the string contains all $needles, false otherwise. By
414 87
     * default the comparison is case-sensitive, but can be made insensitive by
415 87
     * setting $caseSensitive to false.
416 87
     *
417 87
     * @param array $needles       <p>SubStrings to look for.</p>
418
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
419
     *
420
     * @return bool <p>Whether or not $str contains $needle.</p>
421
     */
422
    public function containsAll(array $needles, bool $caseSensitive = true): bool
423
    {
424
        return $this->utf8::str_contains_all(
425
            $this->str,
426
            $needles,
427
            $caseSensitive
428
        );
429
    }
430
431 86
    /**
432
     * Returns true if the string contains any $needles, false otherwise. By
433 86
     * default the comparison is case-sensitive, but can be made insensitive by
434 86
     * setting $caseSensitive to false.
435 86
     *
436 86
     * @param array $needles       <p>SubStrings to look for.</p>
437 86
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
438
     *
439
     * @return bool <p>Whether or not $str contains $needle.</p>
440
     */
441
    public function containsAny(array $needles, bool $caseSensitive = true): bool
442
    {
443
        return $this->utf8::str_contains_any(
444
            $this->str,
445
            $needles,
446 2
            $caseSensitive
447
        );
448 2
    }
449
450
    /**
451
     * Returns the length of the string, implementing the countable interface.
452
     *
453
     * @return int <p>The number of characters in the string, given the encoding.</p>
454
     */
455
    public function count(): int
456
    {
457
        return $this->length();
458
    }
459
460
    /**
461 30
     * Returns the number of occurrences of $substring in the given string.
462
     * By default, the comparison is case-sensitive, but can be made insensitive
463 30
     * by setting $caseSensitive to false.
464 30
     *
465 30
     * @param string $substring     <p>The substring to search for.</p>
466 30
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
467 30
     *
468
     * @return int
469
     */
470
    public function countSubstr(string $substring, bool $caseSensitive = true): int
471
    {
472
        return $this->utf8::substr_count_simple(
473
            $this->str,
474
            $substring,
475
            $caseSensitive,
476
            $this->encoding
477
        );
478
    }
479
480
    /**
481
     * Creates a Stringy object and assigns both str and encoding properties
482
     * the supplied values. $str is cast to a string prior to assignment, and if
483
     * $encoding is not specified, it defaults to mb_internal_encoding(). It
484
     * then returns the initialized object. Throws an InvalidArgumentException
485
     * if the first argument is an array or object without a __toString method.
486 2085
     *
487
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
488 2085
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
489
     *
490
     * @throws \InvalidArgumentException <p>if an array or object without a
491 2085
     *                                   __toString method is passed as the first argument</p>
492
     *
493
     * @return static <p>A Stringy object.</p>
494 2085
     */
495
    public static function create($str = '', string $encoding = null): self
496
    {
497
        return new static($str, $encoding);
498
    }
499
500
    /**
501
     * Returns a lowercase and trimmed string separated by dashes. Dashes are
502
     * inserted before uppercase characters (with the exception of the first
503
     * character of the string), and in place of spaces as well as underscores.
504 38
     *
505
     * @return static <p>Object with a dasherized $str</p>
506 38
     */
507
    public function dasherize(): self
508 38
    {
509
        return static::create(
510
            $this->utf8::str_dasherize($this->str),
511
            $this->encoding
512
        );
513
    }
514
515
    /**
516
     * Returns a lowercase and trimmed string separated by the given delimiter.
517
     * Delimiters are inserted before uppercase characters (with the exception
518
     * of the first character of the string), and in place of spaces, dashes,
519
     * and underscores. Alpha delimiters are not converted to lowercase.
520
     *
521 76
     * @param string $delimiter <p>Sequence used to separate parts of the string.</p>
522
     *
523 76
     * @return static <p>Object with a delimited $str.</p>
524
     */
525 76
    public function delimit(string $delimiter): self
526
    {
527
        return static::create(
528
            $this->utf8::str_delimit($this->str, $delimiter),
529
            $this->encoding
530
        );
531
    }
532
533
    /**
534
     * Returns true if the string ends with $substring, false otherwise. By
535
     * default, the comparison is case-sensitive, but can be made insensitive
536
     * by setting $caseSensitive to false.
537
     *
538 22
     * @param string $substring     <p>The substring to look for.</p>
539
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
540 22
     *
541 14
     * @return bool <p>Whether or not $str ends with $substring.</p>
542
     */
543
    public function endsWith(string $substring, bool $caseSensitive = true): bool
544 8
    {
545
        if ($caseSensitive) {
546
            return $this->utf8::str_ends_with($this->str, $substring);
547
        }
548
549
        return $this->utf8::str_iends_with($this->str, $substring);
550
    }
551
552
    /**
553
     * Returns true if the string ends with any of $substrings, false otherwise.
554
     * By default, the comparison is case-sensitive, but can be made insensitive
555
     * by setting $caseSensitive to false.
556
     *
557 22
     * @param string[] $substrings    <p>Substrings to look for.</p>
558
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
559 22
     *
560 14
     * @return bool <p>Whether or not $str ends with $substring.</p>
561
     */
562
    public function endsWithAny(array $substrings, bool $caseSensitive = true): bool
563 8
    {
564
        if ($caseSensitive) {
565
            return $this->utf8::str_ends_with_any($this->str, $substrings);
566
        }
567
568
        return $this->utf8::str_iends_with_any($this->str, $substrings);
569
    }
570
571
    /**
572
     * Ensures that the string begins with $substring. If it doesn't, it's
573
     * prepended.
574 20
     *
575
     * @param string $substring <p>The substring to add if not present.</p>
576 20
     *
577
     * @return static <p>Object with its $str prefixed by the $substring.</p>
578 20
     */
579
    public function ensureLeft(string $substring): self
580
    {
581
        return static::create(
582
            $this->utf8::str_ensure_left($this->str, $substring),
583
            $this->encoding
584
        );
585
    }
586
587
    /**
588 20
     * Ensures that the string ends with $substring. If it doesn't, it's appended.
589
     *
590 20
     * @param string $substring <p>The substring to add if not present.</p>
591
     *
592 20
     * @return static <p>Object with its $str suffixed by the $substring.</p>
593
     */
594
    public function ensureRight(string $substring): self
595
    {
596
        return static::create(
597
            $this->utf8::str_ensure_right($this->str, $substring),
598
            $this->encoding
599
        );
600 6
    }
601
602 6
    /**
603 6
     * Create a escape html version of the string via "$this->utf8::htmlspecialchars()".
604 6
     *
605 6
     * @return static
606
     */
607
    public function escape(): self
608 6
    {
609
        return static::create(
610
            $this->utf8::htmlspecialchars(
611
                $this->str,
612
                \ENT_QUOTES | \ENT_SUBSTITUTE,
613
                $this->encoding
614
            ),
615
            $this->encoding
616
        );
617
    }
618
619
    /**
620 1
     * Create an extract from a sentence, so if the search-string was found, it try to centered in the output.
621
     *
622 1
     * @param string   $search
623 1
     * @param int|null $length                 [optional] <p>Default: null === text->length / 2</p>
624 1
     * @param string   $replacerForSkippedText [optional] <p>Default: …</p>
625 1
     *
626 1
     * @return static
627 1
     */
628
    public function extractText(string $search = '', int $length = null, string $replacerForSkippedText = '…'): self
629
    {
630 1
        return static::create(
631
            $this->utf8::extract_text(
632
                $this->str,
633
                $search,
634
                $length,
635
                $replacerForSkippedText,
636
                $this->encoding
637
            ),
638
            $this->encoding
639
        );
640 25
    }
641
642 25
    /**
643
     * Returns the first $n characters of the string.
644 25
     *
645
     * @param int $n <p>Number of characters to retrieve from the start.</p>
646
     *
647
     * @return static <p>Object with its $str being the first $n chars.</p>
648
     */
649
    public function first(int $n): self
650
    {
651
        return static::create(
652 5
            $this->utf8::first_char($this->str, $n, $this->encoding),
653
            $this->encoding
654 5
        );
655
    }
656
657
    /**
658
     * Returns the encoding used by the Stringy object.
659
     *
660
     * @return string <p>The current value of the $encoding property.</p>
661
     */
662
    public function getEncoding(): string
663
    {
664
        return $this->encoding;
665 2
    }
666
667 2
    /**
668
     * Returns a new ArrayIterator, thus implementing the IteratorAggregate
669
     * interface. The ArrayIterator's constructor is passed an array of chars
670
     * in the multibyte string. This enables the use of foreach with instances
671
     * of Stringy\Stringy.
672
     *
673
     * @return \ArrayIterator <p>An iterator for the characters in the string.</p>
674
     */
675 24
    public function getIterator(): \ArrayIterator
676
    {
677 24
        return new \ArrayIterator($this->chars());
678
    }
679
680
    /**
681
     * Returns true if the string contains a lower case char, false otherwise.
682
     *
683
     * @return bool <p>Whether or not the string contains a lower case character.</p>
684
     */
685 24
    public function hasLowerCase(): bool
686
    {
687 24
        return $this->utf8::has_lowercase($this->str);
688
    }
689
690
    /**
691
     * Returns true if the string contains an upper case char, false otherwise.
692
     *
693
     * @return bool <p>Whether or not the string contains an upper case character.</p>
694
     */
695
    public function hasUpperCase(): bool
696
    {
697
        return $this->utf8::has_uppercase($this->str);
698
    }
699
700
    /**
701
     * Convert all HTML entities to their applicable characters.
702
     *
703
     * @param int $flags [optional] <p>
704
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
705
     *                   which document type to use. The default is ENT_COMPAT.
706
     *                   <table>
707
     *                   Available <i>flags</i> constants
708
     *                   <tr valign="top">
709
     *                   <td>Constant Name</td>
710
     *                   <td>Description</td>
711
     *                   </tr>
712
     *                   <tr valign="top">
713
     *                   <td><b>ENT_COMPAT</b></td>
714
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
715
     *                   </tr>
716
     *                   <tr valign="top">
717
     *                   <td><b>ENT_QUOTES</b></td>
718
     *                   <td>Will convert both double and single quotes.</td>
719
     *                   </tr>
720
     *                   <tr valign="top">
721
     *                   <td><b>ENT_NOQUOTES</b></td>
722
     *                   <td>Will leave both double and single quotes unconverted.</td>
723
     *                   </tr>
724
     *                   <tr valign="top">
725
     *                   <td><b>ENT_HTML401</b></td>
726
     *                   <td>
727
     *                   Handle code as HTML 4.01.
728
     *                   </td>
729
     *                   </tr>
730
     *                   <tr valign="top">
731
     *                   <td><b>ENT_XML1</b></td>
732
     *                   <td>
733
     *                   Handle code as XML 1.
734
     *                   </td>
735
     *                   </tr>
736
     *                   <tr valign="top">
737
     *                   <td><b>ENT_XHTML</b></td>
738
     *                   <td>
739
     *                   Handle code as XHTML.
740
     *                   </td>
741
     *                   </tr>
742
     *                   <tr valign="top">
743 10
     *                   <td><b>ENT_HTML5</b></td>
744
     *                   <td>
745 10
     *                   Handle code as HTML 5.
746 10
     *                   </td>
747 10
     *                   </tr>
748 10
     *                   </table>
749
     *                   </p>
750
     *
751 10
     * @return static <p>Object with the resulting $str after being html decoded.</p>
752
     */
753 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...
754
    {
755
        return static::create(
756
            $this->utf8::html_entity_decode(
757
                $this->str,
758
                $flags,
759
                $this->encoding
760
            ),
761
            $this->encoding
762
        );
763
    }
764
765
    /**
766
     * Convert all applicable characters to HTML entities.
767
     *
768
     * @param int $flags [optional] <p>
769
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
770
     *                   which document type to use. The default is ENT_COMPAT.
771
     *                   <table>
772
     *                   Available <i>flags</i> constants
773
     *                   <tr valign="top">
774
     *                   <td>Constant Name</td>
775
     *                   <td>Description</td>
776
     *                   </tr>
777
     *                   <tr valign="top">
778
     *                   <td><b>ENT_COMPAT</b></td>
779
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
780
     *                   </tr>
781
     *                   <tr valign="top">
782
     *                   <td><b>ENT_QUOTES</b></td>
783
     *                   <td>Will convert both double and single quotes.</td>
784
     *                   </tr>
785
     *                   <tr valign="top">
786
     *                   <td><b>ENT_NOQUOTES</b></td>
787
     *                   <td>Will leave both double and single quotes unconverted.</td>
788
     *                   </tr>
789
     *                   <tr valign="top">
790
     *                   <td><b>ENT_HTML401</b></td>
791
     *                   <td>
792
     *                   Handle code as HTML 4.01.
793
     *                   </td>
794
     *                   </tr>
795
     *                   <tr valign="top">
796
     *                   <td><b>ENT_XML1</b></td>
797
     *                   <td>
798
     *                   Handle code as XML 1.
799
     *                   </td>
800
     *                   </tr>
801
     *                   <tr valign="top">
802
     *                   <td><b>ENT_XHTML</b></td>
803
     *                   <td>
804
     *                   Handle code as XHTML.
805
     *                   </td>
806
     *                   </tr>
807 10
     *                   <tr valign="top">
808
     *                   <td><b>ENT_HTML5</b></td>
809 10
     *                   <td>
810 10
     *                   Handle code as HTML 5.
811 10
     *                   </td>
812 10
     *                   </tr>
813
     *                   </table>
814
     *                   </p>
815 10
     *
816
     * @return static <p>Object with the resulting $str after being html encoded.</p>
817
     */
818 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...
819
    {
820
        return static::create(
821
            $this->utf8::htmlentities(
822
                $this->str,
823
                $flags,
824 6
                $this->encoding
825
            ),
826 6
            $this->encoding
827
        );
828 6
    }
829
830
    /**
831
     * Capitalizes the first word of the string, replaces underscores with
832
     * spaces, and strips '_id'.
833
     *
834
     * @return static <p>Object with a humanized $str.</p>
835
     */
836
    public function humanize(): self
837
    {
838
        return static::create(
839
            $this->utf8::str_humanize($this->str),
840
            $this->encoding
841 20
        );
842
    }
843 20
844 20
    /**
845 20
     * Returns the index of the first occurrence of $needle in the string,
846 20
     * and false if not found. Accepts an optional offset from which to begin
847 20
     * the search.
848
     *
849
     * @param string $needle <p>Substring to look for.</p>
850
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
851
     *
852
     * @return false|int <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
853
     */
854
    public function indexOf(string $needle, int $offset = 0)
855
    {
856
        return $this->utf8::strpos(
857
            $this->str,
858
            $needle,
859
            $offset,
860
            $this->encoding
861
        );
862
    }
863
864
    /**
865
     * Returns the index of the first occurrence of $needle in the string,
866
     * and false if not found. Accepts an optional offset from which to begin
867
     * the search.
868
     *
869
     * @param string $needle <p>Substring to look for.</p>
870
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
871
     *
872
     * @return false|int <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
873
     */
874
    public function indexOfIgnoreCase(string $needle, int $offset = 0)
875
    {
876
        return $this->utf8::stripos(
877
            $this->str,
878
            $needle,
879
            $offset,
880
            $this->encoding
881
        );
882 20
    }
883
884 20
    /**
885 20
     * Returns the index of the last occurrence of $needle in the string,
886 20
     * and false if not found. Accepts an optional offset from which to begin
887 20
     * the search. Offsets may be negative to count from the last character
888 20
     * in the string.
889
     *
890
     * @param string $needle <p>Substring to look for.</p>
891
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
892
     *
893
     * @return false|int <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
894
     */
895
    public function indexOfLast(string $needle, int $offset = 0)
896
    {
897
        return $this->utf8::strrpos(
898
            $this->str,
899
            $needle,
900
            $offset,
901
            $this->encoding
902
        );
903
    }
904
905
    /**
906
     * Returns the index of the last occurrence of $needle in the string,
907
     * and false if not found. Accepts an optional offset from which to begin
908
     * the search. Offsets may be negative to count from the last character
909
     * in the string.
910
     *
911
     * @param string $needle <p>Substring to look for.</p>
912
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
913
     *
914
     * @return false|int <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
915
     */
916
    public function indexOfLastIgnoreCase(string $needle, int $offset = 0)
917
    {
918
        return $this->utf8::strripos(
919
            $this->str,
920
            $needle,
921 16
            $offset,
922
            $this->encoding
923 16
        );
924 16
    }
925 16
926 16
    /**
927 16
     * Inserts $substring into the string at the $index provided.
928
     *
929
     * @param string $substring <p>String to be inserted.</p>
930 16
     * @param int    $index     <p>The index at which to insert the substring.</p>
931
     *
932
     * @return static <p>Object with the resulting $str after the insertion.</p>
933
     */
934
    public function insert(string $substring, int $index): self
935
    {
936
        return static::create(
937
            $this->utf8::str_insert(
938
                $this->str,
939
                $substring,
940
                $index,
941
                $this->encoding
942
            ),
943
            $this->encoding
944
        );
945 13
    }
946
947 13
    /**
948 1
     * Returns true if the string contains the $pattern, otherwise false.
949
     *
950
     * WARNING: Asterisks ("*") are translated into (".*") zero-or-more regular
951 12
     * expression wildcards.
952 12
     *
953
     * @credit Originally from Laravel, thanks Taylor.
954 12
     *
955
     * @param string $pattern <p>The string or pattern to match against.</p>
956
     *
957
     * @return bool <p>Whether or not we match the provided pattern.</p>
958
     */
959
    public function is(string $pattern): bool
960
    {
961
        if ($this->toString() === $pattern) {
962 20
            return true;
963
        }
964 20
965
        $quotedPattern = \preg_quote($pattern, '/');
966
        $replaceWildCards = \str_replace('\*', '.*', $quotedPattern);
967
968
        return $this->matchesPattern('^' . $replaceWildCards . '\z');
969
    }
970
971
    /**
972 26
     * Returns true if the string contains only alphabetic chars, false otherwise.
973
     *
974 26
     * @return bool <p>Whether or not $str contains only alphabetic chars.</p>
975
     */
976
    public function isAlpha(): bool
977
    {
978
        return $this->utf8::is_alpha($this->str);
979
    }
980
981
    /**
982
     * Returns true if the string contains only alphabetic and numeric chars, false otherwise.
983
     *
984 14
     * @return bool <p>Whether or not $str contains only alphanumeric chars.</p>
985
     */
986 14
    public function isAlphanumeric(): bool
987
    {
988
        return $this->utf8::is_alphanumeric($this->str);
989
    }
990
991
    /**
992
     * Returns true if the string is base64 encoded, false otherwise.
993
     *
994 30
     * @param bool $emptyStringIsValid
995
     *
996 30
     * @return bool <p>Whether or not $str is base64 encoded.</p>
997
     */
998
    public function isBase64($emptyStringIsValid = true): bool
999
    {
1000
        return $this->utf8::is_base64($this->str, $emptyStringIsValid);
1001
    }
1002
1003
    /**
1004
     * Returns true if the string contains only whitespace chars, false otherwise.
1005
     *
1006
     * @return bool <p>Whether or not $str contains only whitespace characters.</p>
1007
     */
1008
    public function isBlank(): bool
1009 1
    {
1010
        return $this->utf8::is_blank($this->str);
1011 1
    }
1012
1013
    /**
1014
     * Returns true if the string contains a valid E-Mail address, false otherwise.
1015
     *
1016
     * @param bool $useExampleDomainCheck   [optional] <p>Default: false</p>
1017
     * @param bool $useTypoInDomainCheck    [optional] <p>Default: false</p>
1018
     * @param bool $useTemporaryDomainCheck [optional] <p>Default: false</p>
1019
     * @param bool $useDnsCheck             [optional] <p>Default: false</p>
1020
     *
1021
     * @return bool <p>Whether or not $str contains a valid E-Mail address.</p>
1022
     */
1023
    public function isEmail(bool $useExampleDomainCheck = false, bool $useTypoInDomainCheck = false, bool $useTemporaryDomainCheck = false, bool $useDnsCheck = false): bool
1024
    {
1025
        return EmailCheck::isValid($this->str, $useExampleDomainCheck, $useTypoInDomainCheck, $useTemporaryDomainCheck, $useDnsCheck);
1026
    }
1027
1028
    /**
1029
     * Determine whether the string is considered to be empty.
1030
     *
1031
     * A variable is considered empty if it does not exist or if its value equals FALSE.
1032 26
     * empty() does not generate a warning if the variable does not exist.
1033
     *
1034 26
     * @return bool <p>Whether or not $str is empty().</p>
1035
     */
1036
    public function isEmpty(): bool
1037
    {
1038
        return $this->utf8::is_empty($this->str);
1039
    }
1040
1041
    /**
1042 1
     * Returns true if the string contains only hexadecimal chars, false otherwise.
1043
     *
1044 1
     * @return bool <p>Whether or not $str contains only hexadecimal chars.</p>
1045
     */
1046
    public function isHexadecimal(): bool
1047
    {
1048
        return $this->utf8::is_hexadecimal($this->str);
1049
    }
1050
1051
    /**
1052
     * Returns true if the string contains HTML-Tags, false otherwise.
1053
     *
1054
     * @return bool <p>Whether or not $str contains HTML-Tags.</p>
1055
     */
1056 40
    public function isHtml(): bool
1057
    {
1058 40
        return $this->utf8::is_html($this->str);
1059
    }
1060
1061
    /**
1062
     * Returns true if the string is JSON, false otherwise. Unlike json_decode
1063
     * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
1064
     * in that an empty string is not considered valid JSON.
1065
     *
1066 16
     * @param bool $onlyArrayOrObjectResultsAreValid
1067
     *
1068 16
     * @return bool <p>Whether or not $str is JSON.</p>
1069
     */
1070
    public function isJson($onlyArrayOrObjectResultsAreValid = false): bool
1071
    {
1072
        return $this->utf8::is_json($this->str, $onlyArrayOrObjectResultsAreValid);
1073
    }
1074
1075
    /**
1076 14
     * Returns true if the string contains only lower case chars, false otherwise.
1077
     *
1078 14
     * @return bool <p>Whether or not $str contains only lower case characters.</p>
1079
     */
1080
    public function isLowerCase(): bool
1081
    {
1082
        return $this->utf8::is_lowercase($this->str);
1083
    }
1084
1085
    /**
1086
     * Returns true if the string is serialized, false otherwise.
1087 16
     *
1088
     * @return bool <p>Whether or not $str is serialized.</p>
1089 16
     */
1090
    public function isSerialized(): bool
1091
    {
1092
        return $this->utf8::is_serialized($this->str);
1093
    }
1094
1095
    /**
1096
     * Returns true if the string contains only lower case chars, false
1097
     * otherwise.
1098
     *
1099 24
     * @return bool <p>Whether or not $str contains only lower case characters.</p>
1100
     */
1101 24
    public function isUpperCase(): bool
1102 24
    {
1103 24
        return $this->utf8::is_uppercase($this->str);
1104 24
    }
1105
1106
    /**
1107 24
     * Returns the last $n characters of the string.
1108
     *
1109
     * @param int $n <p>Number of characters to retrieve from the end.</p>
1110
     *
1111
     * @return static <p>Object with its $str being the last $n chars.</p>
1112
     */
1113
    public function last(int $n): self
1114
    {
1115
        return static::create(
1116
            $this->utf8::str_last_char(
1117
                $this->str,
1118
                $n,
1119 2
                $this->encoding
1120
            ),
1121 2
            $this->encoding
1122
        );
1123 2
    }
1124
1125
    /**
1126
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
1127
     * If no match is found returns new empty Stringy object.
1128
     *
1129
     * @param string $needle       <p>The string to look for.</p>
1130
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
1131
     *
1132
     * @return static
1133
     */
1134 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...
1135 1
    {
1136
        return static::create(
1137 1
            $this->utf8::str_substr_last($this->str, $needle, $beforeNeedle, $this->encoding),
1138
            $this->encoding
1139 1
        );
1140
    }
1141
1142
    /**
1143
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
1144
     * If no match is found returns new empty Stringy object.
1145
     *
1146
     * @param string $needle       <p>The string to look for.</p>
1147 11
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
1148
     *
1149 11
     * @return static
1150
     */
1151 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...
1152
    {
1153
        return static::create(
1154
            $this->utf8::str_isubstr_last($this->str, $needle, $beforeNeedle, $this->encoding),
1155
            $this->encoding
1156
        );
1157
    }
1158
1159 1
    /**
1160
     * Returns the length of the string.
1161 1
     *
1162
     * @return int <p>The number of characters in $str given the encoding.</p>
1163 1
     */
1164
    public function length(): int
1165
    {
1166
        return $this->utf8::strlen($this->str, $this->encoding);
1167
    }
1168
1169
    /**
1170
     * Line-Wrap the string after $limit, but also after the next word.
1171
     *
1172 32
     * @param int $limit
1173
     *
1174 32
     * @return static
1175
     */
1176 32
    public function lineWrapAfterWord(int $limit): self
1177 32
    {
1178
        return static::create(
1179
            $this->utf8::wordwrap_per_line($this->str, $limit),
1180 32
            $this->encoding
1181
        );
1182
    }
1183
1184
    /**
1185
     * Splits on newlines and carriage returns, returning an array of Stringy
1186
     * objects corresponding to the lines in the string.
1187
     *
1188
     * @return static[] <p>An array of Stringy objects.</p>
1189
     */
1190 20
    public function lines(): array
1191
    {
1192 20
        $array = $this->utf8::str_to_lines($this->str);
1193 20
        foreach ($array as $i => &$value) {
1194 20
            $value = static::create($value, $this->encoding);
1195 20
        }
1196
1197
        return $array;
1198 20
    }
1199
1200
    /**
1201
     * Returns the longest common prefix between the string and $otherStr.
1202
     *
1203
     * @param string $otherStr <p>Second string for comparison.</p>
1204
     *
1205
     * @return static <p>Object with its $str being the longest common prefix.</p>
1206
     */
1207
    public function longestCommonPrefix(string $otherStr): self
1208
    {
1209 20
        return static::create(
1210
            $this->utf8::str_longest_common_prefix(
1211 20
                $this->str,
1212 20
                $otherStr,
1213 20
                $this->encoding
1214 20
            ),
1215
            $this->encoding
1216
        );
1217 20
    }
1218
1219
    /**
1220
     * Returns the longest common substring between the string and $otherStr.
1221
     * In the case of ties, it returns that which occurs first.
1222
     *
1223
     * @param string $otherStr <p>Second string for comparison.</p>
1224
     *
1225
     * @return static <p>Object with its $str being the longest common substring.</p>
1226
     */
1227 20
    public function longestCommonSubstring(string $otherStr): self
1228
    {
1229 20
        return static::create(
1230 20
            $this->utf8::str_longest_common_substring(
1231 20
                $this->str,
1232 20
                $otherStr,
1233
                $this->encoding
1234
            ),
1235 20
            $this->encoding
1236
        );
1237
    }
1238
1239
    /**
1240
     * Returns the longest common suffix between the string and $otherStr.
1241
     *
1242
     * @param string $otherStr <p>Second string for comparison.</p>
1243 10
     *
1244
     * @return static <p>Object with its $str being the longest common suffix.</p>
1245 10
     */
1246
    public function longestCommonSuffix(string $otherStr): self
1247 10
    {
1248
        return static::create(
1249
            $this->utf8::str_longest_common_suffix(
1250
                $this->str,
1251
                $otherStr,
1252
                $this->encoding
1253
            ),
1254
            $this->encoding
1255
        );
1256
    }
1257
1258
    /**
1259 12
     * Converts the first character of the string to lower case.
1260
     *
1261 12
     * @return static <p>Object with the first character of $str being lower case.</p>
1262 12
     */
1263 12
    public function lowerCaseFirst(): self
1264 12
    {
1265
        return static::create(
1266
            $this->utf8::lcfirst($this->str, $this->encoding),
1267
            $this->encoding
1268
        );
1269
    }
1270
1271
    /**
1272
     * Returns whether or not a character exists at an index. Offsets may be
1273
     * negative to count from the last character in the string. Implements
1274
     * part of the ArrayAccess interface.
1275
     *
1276
     * @param int $offset <p>The index to check.</p>
1277
     *
1278
     * @return bool <p>Whether or not the index exists.</p>
1279
     */
1280 4
    public function offsetExists($offset): bool
1281
    {
1282 4
        return $this->utf8::str_offset_exists(
1283
            $this->str,
1284
            $offset,
1285
            $this->encoding
1286
        );
1287
    }
1288
1289
    /**
1290
     * Returns the character at the given index. Offsets may be negative to
1291
     * count from the last character in the string. Implements part of the
1292
     * ArrayAccess interface, and throws an OutOfBoundsException if the index
1293
     * does not exist.
1294 2
     *
1295
     * @param int $offset <p>The <strong>index</strong> from which to retrieve the char.</p>
1296
     *
1297
     * @throws \OutOfBoundsException <p>If the positive or negative offset does not exist.</p>
1298 2
     *
1299
     * @return string <p>The character at the specified index.</p>
1300
     */
1301
    public function offsetGet($offset): string
1302
    {
1303
        return $this->utf8::str_offset_get($this->str, $offset, $this->encoding);
1304
    }
1305
1306
    /**
1307
     * Implements part of the ArrayAccess interface, but throws an exception
1308
     * when called. This maintains the immutability of Stringy objects.
1309 2
     *
1310
     * @param int   $offset <p>The index of the character.</p>
1311
     * @param mixed $value  <p>Value to set.</p>
1312
     *
1313 2
     * @throws \Exception <p>When called.</p>
1314
     */
1315
    public function offsetSet($offset, $value)
1316
    {
1317
        // Stringy is immutable, cannot directly set char
1318
        /** @noinspection ThrowRawExceptionInspection */
1319
        throw new \Exception('Stringy object is immutable, cannot modify char');
1320
    }
1321
1322
    /**
1323
     * Implements part of the ArrayAccess interface, but throws an exception
1324
     * when called. This maintains the immutability of Stringy objects.
1325
     *
1326
     * @param int $offset <p>The index of the character.</p>
1327
     *
1328
     * @throws \Exception <p>When called.</p>
1329
     */
1330
    public function offsetUnset($offset)
1331 26
    {
1332
        // Don't allow directly modifying the string
1333 26
        /** @noinspection ThrowRawExceptionInspection */
1334 26
        throw new \Exception('Stringy object is immutable, cannot unset char');
1335 26
    }
1336 26
1337 26
    /**
1338 26
     * Pads the string to a given length with $padStr. If length is less than
1339 26
     * or equal to the length of the string, no padding takes places. The
1340
     * default string used for padding is a space, and the default type (one of
1341
     * 'left', 'right', 'both') is 'right'. Throws an InvalidArgumentException
1342
     * if $padType isn't one of those 3 values.
1343
     *
1344
     * @param int    $length  <p>Desired string length after padding.</p>
1345
     * @param string $padStr  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
1346
     * @param string $padType [optional] <p>One of 'left', 'right', 'both'. Default: 'right'</p>
1347
     *
1348
     * @throws \InvalidArgumentException <p>If $padType isn't one of 'right', 'left' or 'both'.</p>
1349
     *
1350
     * @return static <p>Object with a padded $str.</p>
1351
     */
1352
    public function pad(int $length, string $padStr = ' ', string $padType = 'right'): self
1353 22
    {
1354
        return static::create(
1355 22
            $this->utf8::str_pad(
1356 22
                $this->str,
1357 22
                $length,
1358 22
                $padStr,
1359 22
                $padType,
1360 22
                $this->encoding
1361
            )
1362
        );
1363
    }
1364
1365
    /**
1366
     * Returns a new string of a given length such that both sides of the
1367
     * string are padded. Alias for pad() with a $padType of 'both'.
1368
     *
1369
     * @param int    $length <p>Desired string length after padding.</p>
1370
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
1371
     *
1372
     * @return static <p>String with padding applied.</p>
1373
     */
1374 14
    public function padBoth(int $length, string $padStr = ' '): self
1375
    {
1376 14
        return static::create(
1377 14
            $this->utf8::str_pad_both(
1378 14
                $this->str,
1379 14
                $length,
1380 14
                $padStr,
1381 14
                $this->encoding
1382
            )
1383
        );
1384
    }
1385
1386
    /**
1387
     * Returns a new string of a given length such that the beginning of the
1388
     * string is padded. Alias for pad() with a $padType of 'left'.
1389
     *
1390
     * @param int    $length <p>Desired string length after padding.</p>
1391
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
1392
     *
1393
     * @return static <p>String with left padding.</p>
1394
     */
1395 14
    public function padLeft(int $length, string $padStr = ' '): self
1396
    {
1397 14
        return static::create(
1398 14
            $this->utf8::str_pad_left(
1399 14
                $this->str,
1400 14
                $length,
1401 14
                $padStr,
1402 14
                $this->encoding
1403
            )
1404
        );
1405
    }
1406
1407
    /**
1408
     * Returns a new string of a given length such that the end of the string
1409
     * is padded. Alias for pad() with a $padType of 'right'.
1410
     *
1411
     * @param int    $length <p>Desired string length after padding.</p>
1412
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
1413
     *
1414 4
     * @return static <p>String with right padding.</p>
1415
     */
1416 4
    public function padRight(int $length, string $padStr = ' '): self
1417
    {
1418
        return static::create(
1419
            $this->utf8::str_pad_right(
1420
                $this->str,
1421
                $length,
1422
                $padStr,
1423
                $this->encoding
1424
            )
1425
        );
1426
    }
1427
1428
    /**
1429 19
     * Returns a new string starting with $string.
1430
     *
1431 19
     * @param string $string <p>The string to append.</p>
1432 19
     *
1433 19
     * @return static <p>Object with appended $string.</p>
1434 19
     */
1435 19
    public function prepend(string $string): self
1436 19
    {
1437
        return static::create($string . $this->str, $this->encoding);
1438
    }
1439 19
1440
    /**
1441
     * Replaces all occurrences of $pattern in $str by $replacement.
1442
     *
1443
     * @param string $pattern     <p>The regular expression pattern.</p>
1444
     * @param string $replacement <p>The string to replace with.</p>
1445
     * @param string $options     [optional] <p>Matching conditions to be used.</p>
1446
     * @param string $delimiter   [optional] <p>Delimiter the the regex. Default: '/'</p>
1447
     *
1448
     * @return static <p>Object with the result2ing $str after the replacements.</p>
1449
     */
1450
    public function regexReplace(string $pattern, string $replacement, string $options = '', string $delimiter = '/'): self
1451 6
    {
1452
        return static::create(
1453 6
            $this->utf8::regex_replace(
1454
                $this->str,
1455 6
                $pattern,
1456
                $replacement,
1457
                $options,
1458
                $delimiter
1459
            ),
1460
            $this->encoding
1461
        );
1462
    }
1463
1464
    /**
1465 6
     * Remove html via "strip_tags()" from the string.
1466
     *
1467 6
     * @param string $allowableTags [optional] <p>You can use the optional second parameter to specify tags which should
1468
     *                              not be stripped. Default: null
1469 6
     *                              </p>
1470
     *
1471
     * @return static
1472
     */
1473
    public function removeHtml(string $allowableTags = null): self
1474
    {
1475
        return static::create(
1476
            $this->utf8::remove_html($this->str, $allowableTags . ''),
1477
            $this->encoding
1478
        );
1479 40
    }
1480
1481 40
    /**
1482
     * Remove all breaks [<br> | \r\n | \r | \n | ...] from the string.
1483 40
     *
1484
     * @param string $replacement [optional] <p>Default is a empty string.</p>
1485
     *
1486
     * @return static
1487
     */
1488
    public function removeHtmlBreak(string $replacement = ''): self
1489
    {
1490
        return static::create(
1491
            $this->utf8::remove_html_breaks($this->str, $replacement),
1492
            $this->encoding
1493 40
        );
1494
    }
1495 40
1496
    /**
1497 40
     * Returns a new string with the prefix $substring removed, if present.
1498
     *
1499
     * @param string $substring <p>The prefix to remove.</p>
1500
     *
1501
     * @return static <p>Object having a $str without the prefix $substring.</p>
1502
     */
1503
    public function removeLeft(string $substring): self
1504
    {
1505 6
        return static::create(
1506
            $this->utf8::remove_left($this->str, $substring, $this->encoding),
1507 6
            $this->encoding
1508
        );
1509 6
    }
1510 1
1511
    /**
1512
     * Returns a new string with the suffix $substring removed, if present.
1513 6
     *
1514
     * @param string $substring <p>The suffix to remove.</p>
1515 6
     *
1516
     * @return static <p>Object having a $str without the suffix $substring.</p>
1517
     */
1518
    public function removeRight(string $substring): self
1519
    {
1520
        return static::create(
1521
            $this->utf8::remove_right($this->str, $substring, $this->encoding),
1522
            $this->encoding
1523
        );
1524
    }
1525 14
1526
    /**
1527 14
     * Try to remove all XSS-attacks from the string.
1528
     *
1529 14
     * @return static
1530
     */
1531
    public function removeXss(): self
1532
    {
1533
        static $antiXss = null;
1534
1535
        if ($antiXss === null) {
1536
            $antiXss = new AntiXSS();
1537
        }
1538
1539
        $str = $antiXss->xss_clean($this->str);
1540
1541 45
        return static::create($str, $this->encoding);
1542
    }
1543 45
1544 10
    /**
1545
     * Returns a repeated string given a multiplier.
1546
     *
1547 35
     * @param int $multiplier <p>The number of times to repeat the string.</p>
1548 2
     *
1549
     * @return static <p>Object with a repeated str.</p>
1550
     */
1551 33
    public function repeat(int $multiplier): self
1552 28
    {
1553
        return static::create(
1554 5
            \str_repeat($this->str, $multiplier),
1555
            $this->encoding
1556
        );
1557 33
    }
1558
1559
    /**
1560
     * Replaces all occurrences of $search in $str by $replacement.
1561
     *
1562
     * @param string $search        <p>The needle to search for.</p>
1563
     * @param string $replacement   <p>The string to replace with.</p>
1564
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1565
     *
1566
     * @return static <p>Object with the resulting $str after the replacements.</p>
1567
     */
1568
    public function replace(string $search, string $replacement, bool $caseSensitive = true): self
1569 30
    {
1570
        if ($search === '' && $replacement === '') {
1571 30
            return static::create($this->str, $this->encoding);
1572 23
        }
1573
1574 7
        if ($this->str === '' && $search === '') {
1575
            return static::create($replacement, $this->encoding);
1576
        }
1577 30
1578
        if ($caseSensitive) {
1579
            return static::create(
1580
                $this->utf8::str_replace($search, $replacement, $this->str),
1581
                $this->encoding
1582
            );
1583
        }
1584
1585
        return static::create(
1586
            $this->utf8::str_ireplace($search, $replacement, $this->str),
1587
            $this->encoding
1588 16
        );
1589
    }
1590 16
1591
    /**
1592 16
     * Replaces all occurrences of $search in $str by $replacement.
1593
     *
1594
     * @param array        $search        <p>The elements to search for.</p>
1595
     * @param array|string $replacement   <p>The string to replace with.</p>
1596
     * @param bool         $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1597
     *
1598
     * @return static <p>Object with the resulting $str after the replacements.</p>
1599
     */
1600
    public function replaceAll(array $search, $replacement, bool $caseSensitive = true): self
1601
    {
1602
        if ($caseSensitive) {
1603 15
            return static::create(
1604
                $this->utf8::str_replace($search, $replacement, $this->str),
1605 15
                $this->encoding
1606
            );
1607 15
        }
1608
1609
        return static::create(
1610
            $this->utf8::str_ireplace($search, $replacement, $this->str),
1611
            $this->encoding
1612
        );
1613
    }
1614
1615
    /**
1616
     * Replaces first occurrences of $search from the beginning of string with $replacement.
1617
     *
1618 16
     * @param string $search      <p>The string to search for.</p>
1619
     * @param string $replacement <p>The replacement.</p>
1620 16
     *
1621
     * @return static <p>Object with the resulting $str after the replacements.</p>
1622 16
     */
1623
    public function replaceFirst(string $search, string $replacement): self
1624
    {
1625
        return static::create(
1626
            $this->utf8::str_replace_first($search, $replacement, $this->str),
1627
            $this->encoding
1628
        );
1629
    }
1630
1631
    /**
1632
     * Replaces last occurrences of $search from the ending of string with $replacement.
1633 16
     *
1634
     * @param string $search      <p>The string to search for.</p>
1635 16
     * @param string $replacement <p>The replacement.</p>
1636
     *
1637 16
     * @return static <p>Object with the resulting $str after the replacements.</p>
1638
     */
1639
    public function replaceLast(string $search, string $replacement): self
1640
    {
1641
        return static::create(
1642
            $this->utf8::str_replace_last($search, $replacement, $this->str),
1643
            $this->encoding
1644
        );
1645 10
    }
1646
1647 10
    /**
1648
     * Replaces all occurrences of $search from the beginning of string with $replacement.
1649 10
     *
1650
     * @param string $search      <p>The string to search for.</p>
1651
     * @param string $replacement <p>The replacement.</p>
1652
     *
1653
     * @return static <p>Object with the resulting $str after the replacements.</p>
1654
     */
1655
    public function replaceBeginning(string $search, string $replacement): self
1656
    {
1657
        return static::create(
1658
            $this->utf8::str_replace_beginning($this->str, $search, $replacement),
1659
            $this->encoding
1660
        );
1661
    }
1662
1663
    /**
1664 45
     * Replaces all occurrences of $search from the ending of string with $replacement.
1665
     *
1666 45
     * @param string $search      <p>The string to search for.</p>
1667 45
     * @param string $replacement <p>The replacement.</p>
1668 45
     *
1669 45
     * @return static <p>Object with the resulting $str after the replacements.</p>
1670 45
     */
1671 45
    public function replaceEnding(string $search, string $replacement): self
1672
    {
1673
        return static::create(
1674 45
            $this->utf8::str_replace_ending($this->str, $search, $replacement),
1675
            $this->encoding
1676
        );
1677
    }
1678
1679
    /**
1680
     * Returns a reversed string. A multibyte version of strrev().
1681
     *
1682
     * @return static <p>Object with a reversed $str.</p>
1683
     */
1684
    public function reverse(): self
1685 4
    {
1686
        return static::create($this->utf8::strrev($this->str), $this->encoding);
1687 4
    }
1688
1689 4
    /**
1690
     * Truncates the string to a given length, while ensuring that it does not
1691
     * split words. If $substring is provided, and truncating occurs, the
1692
     * string is further truncated so that the substring may be appended without
1693
     * exceeding the desired length.
1694
     *
1695
     * @param int    $length    <p>Desired length of the truncated string.</p>
1696
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
1697
     * @param bool   $ignoreDoNotSplitWordsForOneWord
1698 6
     *
1699
     * @return static <p>Object with the resulting $str after truncating.</p>
1700 6
     */
1701
    public function safeTruncate(int $length, string $substring = '', bool $ignoreDoNotSplitWordsForOneWord = true): self
1702 6
    {
1703
        return static::create(
1704
            $this->utf8::str_truncate_safe(
1705
                $this->str,
1706
                $length,
1707
                $substring,
1708
                $this->encoding,
1709
                $ignoreDoNotSplitWordsForOneWord
1710
            ),
1711
            $this->encoding
1712
        );
1713
    }
1714
1715
    /**
1716 34
     * Shorten the string after $length, but also after the next word.
1717
     *
1718 34
     * @param int    $length
1719
     * @param string $strAddOn [optional] <p>Default: '…'</p>
1720 34
     *
1721
     * @return static
1722
     */
1723
    public function shortenAfterWord(int $length, string $strAddOn = '…'): self
1724
    {
1725
        return static::create(
1726
            $this->utf8::str_limit_after_word($this->str, $length, $strAddOn),
1727
            $this->encoding
1728
        );
1729
    }
1730
1731
    /**
1732
     * A multibyte string shuffle function. It returns a string with its
1733
     * characters in random order.
1734
     *
1735
     * @return static <p>Object with a shuffled $str.</p>
1736 16
     */
1737
    public function shuffle(): self
1738 16
    {
1739 16
        return static::create($this->utf8::str_shuffle($this->str), $this->encoding);
1740 16
    }
1741 16
1742 16
    /**
1743
     * Returns the substring beginning at $start, and up to, but not including
1744 16
     * the index specified by $end. If $end is omitted, the function extracts
1745 16
     * the remaining string. If $end is negative, it is computed from the end
1746
     * of the string.
1747
     *
1748
     * @param int $start <p>Initial index from which to begin extraction.</p>
1749
     * @param int $end   [optional] <p>Index at which to end extraction. Default: null</p>
1750
     *
1751
     * @return static <p>Object with its $str being the extracted substring.</p>
1752
     */
1753
    public function slice(int $start, int $end = null): self
1754
    {
1755
        return static::create(
1756
            $this->utf8::str_slice($this->str, $start, $end, $this->encoding),
1757
            $this->encoding
1758
        );
1759
    }
1760
1761 15
    /**
1762
     * Converts the string into an URL slug. This includes replacing non-ASCII
1763 15
     * characters with their closest ASCII equivalents, removing remaining
1764
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
1765 15
     * $replacement. The replacement defaults to a single dash, and the string
1766
     * is also converted to lowercase. The language of the source string can
1767
     * also be supplied for language-specific transliteration.
1768
     *
1769
     * @param string $replacement The string used to replace whitespace
1770
     * @param string $language    Language of the source string
1771
     *
1772
     * @return static Object whose $str has been converted to an URL slug
1773 20
     */
1774
    public function slugify(string $replacement = '-', string $language = 'en'): self
1775 20
    {
1776
        $stringy = self::create($this->str);
1777 20
1778
        $split = \preg_split('/[-_]/', $language);
1779
        $language = \strtolower($split[0]);
1780
        $languageSpecific = [
1781
            'de' => [['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü'], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE']],
1782
            'bg' => [
1783
                ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'],
1784
                ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'],
1785
            ],
1786
        ];
1787
        if (!empty($languageSpecific[$language])) {
1788
            $stringy->str = \str_replace($languageSpecific[$language][0], $languageSpecific[$language][1], $stringy->str);
1789
        }
1790 35
1791
        foreach ($this->charsArray() as $key => $value) {
1792 35
            $stringy->str = \str_replace($value, $key, $stringy->str);
1793 7
        }
1794
        $stringy->str = \str_replace('@', $replacement, $stringy->str);
1795
1796 35
        $stringy->str = \preg_replace(
1797 35
            '/[^a-zA-Z\d\s\-_' . \preg_quote($replacement, '/') . ']/u',
1798 31
            '',
1799
            $stringy->str
1800
        );
1801 35
        $stringy->str = \preg_replace("/^['\s']+|['\s']+\$/", '', \strtolower($stringy->str));
1802
        $stringy->str = \preg_replace('/\B([A-Z])/', '/-\1/', $stringy->str);
1803
        $stringy->str = \preg_replace('/[-_\s]+/', $replacement, $stringy->str);
1804
1805
        $l = \strlen($replacement);
1806 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...
1807
            $stringy->str = \substr($stringy->str, $l);
1808
        }
1809
1810 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...
1811
            $stringy->str = \substr($stringy->str, 0, \strlen($stringy->str) - $l);
1812
        }
1813
1814 22
        return static::create($stringy->str, $this->encoding);
1815
    }
1816 22
1817 14
    /**
1818
     * Converts the string into an URL slug. This includes replacing non-ASCII
1819
     * characters with their closest ASCII equivalents, removing remaining
1820 8
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
1821
     * $replacement. The replacement defaults to a single dash, and the string
1822
     * is also converted to lowercase.
1823
     *
1824
     * @param string $replacement [optional] <p>The string used to replace whitespace. Default: '-'</p>
1825
     * @param string $language    [optional] <p>The language for the url. Default: 'de'</p>
1826
     * @param bool   $strToLower  [optional] <p>string to lower. Default: true</p>
1827
     *
1828
     * @return static <p>Object whose $str has been converted to an URL slug.</p>
1829
     */
1830
    public function urlify(string $replacement = '-', string $language = 'de', bool $strToLower = true): self
1831
    {
1832
        return static::create(
1833 23
            URLify::slug($this->str, $language, $replacement, $strToLower),
1834
            $this->encoding
1835 23
        );
1836 15
    }
1837
1838
    /**
1839 8
     * Convert a string to e.g.: "snake_case"
1840
     *
1841
     * @return static <p>Object with $str in snake_case.</p>
1842
     */
1843
    public function snakeize(): self
1844
    {
1845
        return static::create(
1846
            $this->utf8::str_snakeize($this->str, $this->encoding),
1847
            $this->encoding
1848 24
        );
1849
    }
1850 24
1851
    /**
1852 24
     * Splits the string with the provided regular expression, returning an
1853
     * array of Stringy objects. An optional integer $limit will truncate the
1854
     * results.
1855
     *
1856
     * @param string $pattern <p>The regex with which to split the string.</p>
1857
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no limit</p>
1858
     *
1859
     * @return static[] <p>An array of Stringy objects.</p>
1860 1
     */
1861
    public function split(string $pattern, int $limit = null): array
1862 1
    {
1863
        if ($limit === null) {
1864 1
            $limit = -1;
1865
        }
1866
1867
        $array = $this->utf8::str_split_pattern($this->str, $pattern, $limit);
1868
        foreach ($array as $i => &$value) {
1869
            $value = static::create($value, $this->encoding);
1870
        }
1871
1872
        return $array;
1873
    }
1874 1
1875
    /**
1876 1
     * Returns true if the string begins with $substring, false otherwise. By
1877
     * default, the comparison is case-sensitive, but can be made insensitive
1878 1
     * by setting $caseSensitive to false.
1879
     *
1880
     * @param string $substring     <p>The substring to look for.</p>
1881
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1882
     *
1883
     * @return bool <p>Whether or not $str starts with $substring.</p>
1884
     */
1885
    public function startsWith(string $substring, bool $caseSensitive = true): bool
1886
    {
1887
        if ($caseSensitive) {
1888
            return $this->utf8::str_starts_with($this->str, $substring);
1889
        }
1890
1891 18
        return $this->utf8::str_istarts_with($this->str, $substring);
1892
    }
1893 18
1894 18
    /**
1895 18
     * Returns true if the string begins with any of $substrings, false otherwise.
1896 18
     * By default the comparison is case-sensitive, but can be made insensitive by
1897 18
     * setting $caseSensitive to false.
1898
     *
1899
     * @param array $substrings    <p>Substrings to look for.</p>
1900 18
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1901
     *
1902
     * @return bool <p>Whether or not $str starts with $substring.</p>
1903
     */
1904
    public function startsWithAny(array $substrings, bool $caseSensitive = true): bool
1905
    {
1906
        if ($caseSensitive) {
1907
            return $this->utf8::str_starts_with_any($this->str, $substrings);
1908
        }
1909
1910
        return $this->utf8::str_istarts_with_any($this->str, $substrings);
1911
    }
1912 2
1913
    /**
1914 2
     * Strip all whitespace characters. This includes tabs and newline characters,
1915
     * as well as multibyte whitespace such as the thin space and ideographic space.
1916 2
     *
1917
     * @return static
1918
     */
1919
    public function stripWhitespace(): self
1920
    {
1921
        return static::create(
1922
            $this->utf8::strip_whitespace($this->str),
1923
            $this->encoding
1924
        );
1925
    }
1926
1927
    /**
1928 2
     * Remove css media-queries.
1929
     *
1930 2
     * @return static
1931
     */
1932 2
    public function stripeCssMediaQueries(): self
1933
    {
1934
        return static::create(
1935
            $this->utf8::css_stripe_media_queries($this->str),
1936
            $this->encoding
1937
        );
1938
    }
1939
1940
    /**
1941
     * Remove empty html-tag.
1942 10
     *
1943
     * e.g.: <tag></tag>
1944 10
     *
1945
     * @return static
1946 10
     */
1947
    public function stripeEmptyHtmlTags(): self
1948
    {
1949
        return static::create(
1950
            $this->utf8::html_stripe_empty_tags($this->str),
1951
            $this->encoding
1952
        );
1953
    }
1954 10
1955
    /**
1956 10
     * Returns the substring beginning at $start with the specified $length.
1957
     * It differs from the $this->utf8::substr() function in that providing a $length of
1958 10
     * null will return the rest of the string, rather than an empty string.
1959
     *
1960
     * @param int $start  <p>Position of the first character to use.</p>
1961
     * @param int $length [optional] <p>Maximum number of characters used. Default: null</p>
1962
     *
1963
     * @return static <p>Object with its $str being the substring.</p>
1964
     */
1965
    public function substr(int $start, int $length = null): self
1966
    {
1967
        return static::create(
1968 8
            $this->utf8::substr(
1969
                $this->str,
1970 8
                $start,
1971
                $length,
1972 8
                $this->encoding
1973
            ),
1974
            $this->encoding
1975
        );
1976
    }
1977
1978
    /**
1979
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
1980
     * If no match is found returns new empty Stringy object.
1981
     *
1982
     * @param string $needle       <p>The string to look for.</p>
1983
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
1984 10
     *
1985
     * @return static
1986 10
     */
1987 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...
1988 10
    {
1989
        return static::create(
1990
            $this->utf8::str_substr_first($this->str, $needle, $beforeNeedle, $this->encoding),
1991
            $this->encoding
1992
        );
1993
    }
1994
1995
    /**
1996
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
1997
     * If no match is found returns new empty Stringy object.
1998
     *
1999
     * @param string $needle       <p>The string to look for.</p>
2000
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2001
     *
2002
     * @return static
2003
     */
2004 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...
2005 35
    {
2006
        return static::create(
2007 35
            $this->utf8::str_isubstr_first($this->str, $needle, $beforeNeedle, $this->encoding),
2008
            $this->encoding
2009 35
        );
2010
    }
2011
2012
    /**
2013
     * Surrounds $str with the given substring.
2014
     *
2015
     * @param string $substring <p>The substring to add to both sides.</P>
2016
     *
2017
     * @return static <p>Object whose $str had the substring both prepended and appended.</p>
2018
     */
2019
    public function surround(string $substring): self
2020
    {
2021
        return static::create(
2022 16
            $substring . $this->str . $substring,
2023
            $this->encoding
2024 16
        );
2025
    }
2026 16
2027
    /**
2028
     * Returns a case swapped version of the string.
2029
     *
2030
     * @return static <p>Object whose $str has each character's case swapped.</P>
2031
     */
2032
    public function swapCase(): self
2033
    {
2034
        return static::create(
2035
            $this->utf8::swapCase($this->str, $this->encoding),
2036
            $this->encoding
2037
        );
2038
    }
2039
2040
    /**
2041
     * Returns a string with smart quotes, ellipsis characters, and dashes from
2042
     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
2043 37
     * equivalents.
2044
     *
2045
     * @return static <p>Object whose $str has those characters removed.</p>
2046 37
     */
2047
    public function tidy(): self
2048 37
    {
2049 37
        return static::create(
2050 2
            $this->utf8::normalize_msword($this->str),
2051
            $this->encoding
2052
        );
2053 37
    }
2054 37
2055
    /**
2056
     * Returns a trimmed string with the first letter of each word capitalized.
2057 37
     * Also accepts an array, $ignore, allowing you to list words not to be
2058 36
     * capitalized.
2059
     *
2060
     * @param array|null $ignore [optional] <p>An array of words not to capitalize or null. Default: null</p>
2061 37
     *
2062
     * @return static <p>Object with a titleized $str.</p>
2063
     */
2064
    public function titleize(array $ignore = null): self
2065
    {
2066
        return static::create(
2067
            $this->utf8::str_titleize($this->str, $ignore, $this->encoding),
2068
            $this->encoding
2069
        );
2070
    }
2071
2072
    /**
2073
     * Returns a trimmed string in proper title case.
2074
     *
2075 30
     * Also accepts an array, $ignore, allowing you to list words not to be
2076
     * capitalized.
2077 30
     *
2078
     * Adapted from John Gruber's script.
2079
     *
2080
     * @see https://gist.github.com/gruber/9f9e8650d68b13ce4d78
2081
     *
2082
     * @param array $ignore <p>An array of words not to capitalize.</p>
2083
     *
2084
     * @return static <p>Object with a titleized $str</p>
2085 28
     */
2086
    public function titleizeForHumans(array $ignore = []): self
2087 28
    {
2088
        return static::create(
2089 28
            $this->utf8::str_titleize_for_humans($this->str, $ignore, $this->encoding),
2090
            $this->encoding
2091
        );
2092
    }
2093
2094
    /**
2095
     * Returns an ASCII version of the string. A set of non-ASCII characters are
2096
     * replaced with their closest ASCII counterparts, and the rest are removed
2097
     * unless instructed otherwise.
2098
     *
2099
     * @param bool $strict [optional] <p>Use "transliterator_transliterate()" from PHP-Intl | WARNING: bad performance |
2100 12
     *                     Default: false</p>
2101
     *
2102 12
     * @return static <p>Object whose $str contains only ASCII characters.</p>
2103
     */
2104 12
    public function toTransliterate(bool $strict = false): self
2105
    {
2106
        return static::create(
2107
            $this->utf8::to_ascii($this->str, '?', $strict),
2108
            $this->encoding
2109
        );
2110
    }
2111
2112
    /**
2113 1071
     * Returns an ASCII version of the string. A set of non-ASCII characters are
2114
     * replaced with their closest ASCII counterparts, and the rest are removed
2115 1071
     * by default. The language or locale of the source string can be supplied
2116
     * for language-specific transliteration in any of the following formats:
2117
     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
2118
     * to "aeoeue" rather than "aou" as in other languages.
2119
     *
2120
     * @param string $language          Language of the source string
2121
     * @param bool   $removeUnsupported Whether or not to remove the
2122
     *                                  unsupported characters
2123
     *
2124
     * @return static Object whose $str contains only ASCII characters
2125
     */
2126
    public function toAscii(string $language = 'en', bool $removeUnsupported = true)
2127 10
    {
2128
        // init
2129 10
        $str = $this->str;
2130
2131 10
        $langSpecific = self::langSpecificCharsArray($language);
2132
        if (!empty($langSpecific)) {
2133
            $str = \str_replace($langSpecific[0], $langSpecific[1], $str);
2134
        }
2135
2136
        foreach ($this->charsArray() as $key => $value) {
2137
            $str = \str_replace($value, $key, $str);
2138
        }
2139
2140 10
        if ($removeUnsupported) {
2141
            $str = \preg_replace('/[^\x20-\x7E]/u', '', $str);
2142 10
        }
2143
2144 10
        return static::create($str, $this->encoding);
2145
    }
2146
2147
    /**
2148
     * Returns a boolean representation of the given logical string value.
2149
     * For example, 'true', '1', 'on' and 'yes' will return true. 'false', '0',
2150
     * 'off', and 'no' will return false. In all instances, case is ignored.
2151
     * For other numeric strings, their sign will determine the return value.
2152 10
     * In addition, blank strings consisting of only whitespace will return
2153
     * false. For all other strings, the return value is a result of a
2154 10
     * boolean cast.
2155
     *
2156 10
     * @return bool <p>A boolean value for the string.</p>
2157
     */
2158
    public function toBoolean(): bool
2159
    {
2160
        return $this->utf8::to_boolean($this->str);
2161
    }
2162
2163
    /**
2164
     * Converts all characters in the string to lowercase.
2165
     *
2166
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
2167
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
2168 24
     *
2169
     * @return static <p>Object with all characters of $str being lowercase.</p>
2170 24
     */
2171 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...
2172 24
    {
2173
        return static::create(
2174
            $this->utf8::strtolower(
2175
                $this->str, $this->encoding, false, $lang, $tryToKeepStringLength
2176
            ),
2177
            $this->encoding
2178
        );
2179
    }
2180
2181
    /**
2182
     * Converts each tab in the string to some number of spaces, as defined by
2183
     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
2184 26
     *
2185
     * @param int $tabLength [optional] <p>Number of spaces to replace each tab with. Default: 4</p>
2186 26
     *
2187
     * @return static <p>Object whose $str has had tabs switched to spaces.</p>
2188 26
     */
2189 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...
2190
    {
2191
        if ($tabLength === 4) {
2192
            $tab = '    ';
2193
        } elseif ($tabLength === 2) {
2194
            $tab = '  ';
2195
        } else {
2196
            $tab = \str_repeat(' ', $tabLength);
2197
        }
2198
2199
        return static::create(
2200 26
            \str_replace("\t", $tab, $this->str),
2201
            $this->encoding
2202 26
        );
2203
    }
2204 26
2205
    /**
2206
     * Return Stringy object as string, but you can also use (string) for automatically casting the object into a
2207
     * string.
2208
     *
2209
     * @return string
2210
     */
2211
    public function toString(): string
2212
    {
2213
        return (string) $this->str;
2214
    }
2215
2216
    /**
2217 44
     * Converts each occurrence of some consecutive number of spaces, as
2218
     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
2219 44
     * are converted to a tab.
2220
     *
2221 44
     * @param int $tabLength [optional] <p>Number of spaces to replace with a tab. Default: 4</p>
2222
     *
2223
     * @return static <p>Object whose $str has had spaces switched to tabs.</p>
2224
     */
2225 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...
2226
    {
2227
        if ($tabLength === 4) {
2228
            $tab = '    ';
2229
        } elseif ($tabLength === 2) {
2230
            $tab = '  ';
2231
        } else {
2232 32
            $tab = \str_repeat(' ', $tabLength);
2233
        }
2234 32
2235
        return static::create(
2236
            \str_replace($tab, "\t", $this->str),
2237
            $this->encoding
2238
        );
2239
    }
2240
2241
    /**
2242
     * Converts the first character of each word in the string to uppercase
2243
     * and all other chars to lowercase.
2244 26
     *
2245
     * @return static <p>Object with all characters of $str being title-cased.</p>
2246 26
     */
2247
    public function toTitleCase(): self
2248 26
    {
2249
        return static::create(
2250
            $this->utf8::titlecase($this->str, $this->encoding),
2251
            $this->encoding
2252
        );
2253
    }
2254
2255
    /**
2256 12
     * Converts all characters in the string to uppercase.
2257
     *
2258 12
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
2259
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
2260 12
     *
2261
     * @return static <p>Object with all characters of $str being uppercase.</p>
2262
     */
2263 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...
2264
    {
2265
        return static::create(
2266
            $this->utf8::strtoupper($this->str, $this->encoding, false, $lang, $tryToKeepStringLength),
2267
            $this->encoding
2268 1
        );
2269
    }
2270 1
2271
    /**
2272 1
     * Returns a string with whitespace removed from the start and end of the
2273
     * string. Supports the removal of unicode whitespace. Accepts an optional
2274
     * string of characters to strip instead of the defaults.
2275
     *
2276
     * @param string $chars [optional] <p>String of characters to strip. Default: null</p>
2277
     *
2278
     * @return static <p>Object with a trimmed $str.</p>
2279
     */
2280 37
    public function trim(string $chars = null): self
2281
    {
2282 37
        return static::create(
2283
            $this->utf8::trim($this->str, $chars),
2284 37
            $this->encoding
2285 36
        );
2286
    }
2287
2288
    /**
2289 1
     * Returns a string with whitespace removed from the start of the string.
2290
     * Supports the removal of unicode whitespace. Accepts an optional
2291
     * string of characters to strip instead of the defaults.
2292
     *
2293
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
2294
     *
2295
     * @return static <p>Object with a trimmed $str.</p>
2296
     */
2297
    public function trimLeft(string $chars = null): self
2298
    {
2299
        return static::create(
2300
            $this->utf8::ltrim($this->str, $chars),
2301
            $this->encoding
2302
        );
2303
    }
2304
2305
    /**
2306
     * Returns a string with whitespace removed from the end of the string.
2307
     * Supports the removal of unicode whitespace. Accepts an optional
2308
     * string of characters to strip instead of the defaults.
2309
     *
2310
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
2311
     *
2312
     * @return static <p>Object with a trimmed $str.</p>
2313
     */
2314
    public function trimRight(string $chars = null): self
2315
    {
2316
        return static::create(
2317
            $this->utf8::rtrim($this->str, $chars),
2318
            $this->encoding
2319
        );
2320
    }
2321
2322
    /**
2323
     * Truncates the string to a given length. If $substring is provided, and
2324
     * truncating occurs, the string is further truncated so that the substring
2325
     * may be appended without exceeding the desired length.
2326
     *
2327
     * @param int    $length    <p>Desired length of the truncated string.</p>
2328
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
2329
     *
2330
     * @return static <p>Object with the resulting $str after truncating.</p>
2331
     */
2332
    public function truncate(int $length, string $substring = ''): self
2333
    {
2334
        return static::create(
2335
            $this->utf8::str_truncate($this->str, $length, $substring, $this->encoding),
2336
            $this->encoding
2337
        );
2338
    }
2339
2340
    /**
2341
     * Returns a lowercase and trimmed string separated by underscores.
2342
     * Underscores are inserted before uppercase characters (with the exception
2343
     * of the first character of the string), and in place of spaces as well as
2344
     * dashes.
2345
     *
2346
     * @return static <p>Object with an underscored $str.</p>
2347
     */
2348
    public function underscored(): self
2349
    {
2350
        return $this->delimit('_');
2351
    }
2352
2353
    /**
2354
     * Returns an UpperCamelCase version of the supplied string. It trims
2355
     * surrounding spaces, capitalizes letters following digits, spaces, dashes
2356
     * and underscores, and removes spaces, dashes, underscores.
2357
     *
2358
     * @return static <p>Object with $str in UpperCamelCase.</p>
2359
     */
2360
    public function upperCamelize(): self
2361
    {
2362
        return static::create(
2363
            $this->utf8::str_upper_camelize($this->str, $this->encoding),
2364
            $this->encoding
2365
        );
2366
    }
2367
2368
    /**
2369
     * Converts the first character of the supplied string to upper case.
2370
     *
2371
     * @return static <p>Object with the first character of $str being upper case.</p>
2372
     */
2373
    public function upperCaseFirst(): self
2374
    {
2375
        return static::create($this->utf8::ucfirst($this->str, $this->encoding), $this->encoding);
2376
    }
2377
2378
    /**
2379
     * Converts the string into an valid UTF-8 string.
2380
     *
2381
     * @return static
2382
     */
2383
    public function utf8ify(): self
2384
    {
2385
        return static::create($this->utf8::cleanup($this->str), $this->encoding);
2386
    }
2387
2388
    /**
2389
     * Returns the replacements for the toAscii() method.
2390
     *
2391
     * @return array an array of replacements
2392
     */
2393
    protected function charsArray(): array
2394
    {
2395
        static $charsArray;
2396
2397
        if (isset($charsArray)) {
2398
            return $charsArray;
2399
        }
2400
2401
        return $charsArray = [
2402
            '0'    => ['°', '₀', '۰', '0'],
2403
            '1'    => ['¹', '₁', '۱', '1'],
2404
            '2'    => ['²', '₂', '۲', '2'],
2405
            '3'    => ['³', '₃', '۳', '3'],
2406
            '4'    => ['⁴', '₄', '۴', '٤', '4'],
2407
            '5'    => ['⁵', '₅', '۵', '٥', '5'],
2408
            '6'    => ['⁶', '₆', '۶', '٦', '6'],
2409
            '7'    => ['⁷', '₇', '۷', '7'],
2410
            '8'    => ['⁸', '₈', '۸', '8'],
2411
            '9'    => ['⁹', '₉', '۹', '9'],
2412
            'a'    => [
2413
                'à',
2414
                'á',
2415
                'ả',
2416
                'ã',
2417
                'ạ',
2418
                'ă',
2419
                'ắ',
2420
                'ằ',
2421
                'ẳ',
2422
                'ẵ',
2423
                'ặ',
2424
                'â',
2425
                'ấ',
2426
                'ầ',
2427
                'ẩ',
2428
                'ẫ',
2429
                'ậ',
2430
                'ā',
2431
                'ą',
2432
                'å',
2433
                'α',
2434
                'ά',
2435
                'ἀ',
2436
                'ἁ',
2437
                'ἂ',
2438
                'ἃ',
2439
                'ἄ',
2440
                'ἅ',
2441
                'ἆ',
2442
                'ἇ',
2443
                'ᾀ',
2444
                'ᾁ',
2445
                'ᾂ',
2446
                'ᾃ',
2447
                'ᾄ',
2448
                'ᾅ',
2449
                'ᾆ',
2450
                'ᾇ',
2451
                'ὰ',
2452
                'ά',
2453
                'ᾰ',
2454
                'ᾱ',
2455
                'ᾲ',
2456
                'ᾳ',
2457
                'ᾴ',
2458
                'ᾶ',
2459
                'ᾷ',
2460 12
                'а',
2461
                'أ',
2462 12
                'အ',
2463
                'ာ',
2464
                'ါ',
2465
                'ǻ',
2466
                'ǎ',
2467
                'ª',
2468
                'ა',
2469
                'अ',
2470
                'ا',
2471
                'a',
2472
                'ä',
2473
            ],
2474 37
            'b'    => ['б', 'β', 'ب', 'ဗ', 'ბ', 'b'],
2475
            'c'    => ['ç', 'ć', 'č', 'ĉ', 'ċ', 'c'],
2476 37
            'd'    => [
2477 37
                'ď',
2478 37
                'ð',
2479
                'đ',
2480 37
                'ƌ',
2481 35
                'ȡ',
2482
                'ɖ',
2483
                'ɗ',
2484
                'ᵭ',
2485 2
                'ᶁ',
2486
                'ᶑ',
2487
                'д',
2488
                'δ',
2489
                'د',
2490
                'ض',
2491
                'ဍ',
2492
                'ဒ',
2493
                'დ',
2494
                'd',
2495 2
            ],
2496
            'e'    => [
2497 2
                'é',
2498
                'è',
2499
                'ẻ',
2500
                'ẽ',
2501
                'ẹ',
2502
                'ê',
2503
                'ế',
2504
                'ề',
2505
                'ể',
2506
                'ễ',
2507
                'ệ',
2508
                'ë',
2509
                'ē',
2510
                'ę',
2511
                'ě',
2512
                'ĕ',
2513
                'ė',
2514
                'ε',
2515
                'έ',
2516
                'ἐ',
2517
                'ἑ',
2518
                'ἒ',
2519
                'ἓ',
2520
                'ἔ',
2521
                'ἕ',
2522
                'ὲ',
2523
                'έ',
2524
                'е',
2525
                'ё',
2526
                'э',
2527
                'є',
2528
                'ə',
2529
                'ဧ',
2530
                'ေ',
2531
                'ဲ',
2532
                'ე',
2533
                'ए',
2534
                'إ',
2535
                'ئ',
2536
                'e',
2537
            ],
2538
            'f'    => ['ф', 'φ', 'ف', 'ƒ', 'ფ', 'f'],
2539
            'g'    => [
2540
                'ĝ',
2541
                'ğ',
2542
                'ġ',
2543
                'ģ',
2544
                'г',
2545
                'ґ',
2546
                'γ',
2547
                'ဂ',
2548
                'გ',
2549
                'گ',
2550
                'g',
2551
            ],
2552
            'h'    => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ', 'h'],
2553
            'i'    => [
2554
                'í',
2555
                'ì',
2556
                'ỉ',
2557
                'ĩ',
2558
                'ị',
2559
                'î',
2560
                'ï',
2561
                'ī',
2562
                'ĭ',
2563
                'į',
2564
                'ı',
2565
                'ι',
2566
                'ί',
2567
                'ϊ',
2568
                'ΐ',
2569
                'ἰ',
2570
                'ἱ',
2571
                'ἲ',
2572
                'ἳ',
2573
                'ἴ',
2574
                'ἵ',
2575
                'ἶ',
2576
                'ἷ',
2577
                'ὶ',
2578
                'ί',
2579
                'ῐ',
2580
                'ῑ',
2581
                'ῒ',
2582
                'ΐ',
2583
                'ῖ',
2584
                'ῗ',
2585
                'і',
2586
                'ї',
2587
                'и',
2588
                'ဣ',
2589
                'ိ',
2590
                'ီ',
2591
                'ည်',
2592
                'ǐ',
2593
                'ი',
2594
                'इ',
2595
                'ی',
2596
                'i',
2597
            ],
2598
            'j'    => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج', 'j'],
2599
            'k'    => [
2600
                'ķ',
2601
                'ĸ',
2602
                'к',
2603
                'κ',
2604
                'Ķ',
2605
                'ق',
2606
                'ك',
2607
                'က',
2608
                'კ',
2609
                'ქ',
2610
                'ک',
2611
                'k',
2612
            ],
2613
            'l'    => [
2614
                'ł',
2615
                'ľ',
2616
                'ĺ',
2617
                'ļ',
2618
                'ŀ',
2619
                'л',
2620
                'λ',
2621
                'ل',
2622
                'လ',
2623
                'ლ',
2624
                'l',
2625
            ],
2626
            'm'    => ['м', 'μ', 'م', 'မ', 'მ', 'm'],
2627
            'n'    => [
2628
                'ñ',
2629
                'ń',
2630
                'ň',
2631
                'ņ',
2632
                'ʼn',
2633
                'ŋ',
2634
                'ν',
2635
                'н',
2636
                'ن',
2637
                'န',
2638
                'ნ',
2639
                'n',
2640
            ],
2641
            'o'    => [
2642
                'ó',
2643
                'ò',
2644
                'ỏ',
2645
                'õ',
2646
                'ọ',
2647
                'ô',
2648
                'ố',
2649
                'ồ',
2650
                'ổ',
2651
                'ỗ',
2652
                'ộ',
2653
                'ơ',
2654
                'ớ',
2655
                'ờ',
2656
                'ở',
2657
                'ỡ',
2658
                'ợ',
2659
                'ø',
2660
                'ō',
2661
                'ő',
2662
                'ŏ',
2663
                'ο',
2664
                'ὀ',
2665
                'ὁ',
2666
                'ὂ',
2667
                'ὃ',
2668
                'ὄ',
2669
                'ὅ',
2670
                'ὸ',
2671
                'ό',
2672
                'о',
2673
                'و',
2674
                'θ',
2675
                'ို',
2676
                'ǒ',
2677
                'ǿ',
2678
                'º',
2679
                'ო',
2680
                'ओ',
2681
                'o',
2682
                'ö',
2683
            ],
2684
            'p'    => ['п', 'π', 'ပ', 'პ', 'پ', 'p'],
2685
            'q'    => ['ყ', 'q'],
2686
            'r'    => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ', 'r'],
2687
            's'    => [
2688
                'ś',
2689
                'š',
2690
                'ş',
2691
                'с',
2692
                'σ',
2693
                'ș',
2694
                'ς',
2695
                'س',
2696
                'ص',
2697
                'စ',
2698
                'ſ',
2699
                'ს',
2700
                's',
2701
            ],
2702
            't'    => [
2703
                'ť',
2704
                'ţ',
2705
                'т',
2706
                'τ',
2707
                'ț',
2708
                'ت',
2709
                'ط',
2710
                'ဋ',
2711
                'တ',
2712
                'ŧ',
2713
                'თ',
2714
                'ტ',
2715
                't',
2716
            ],
2717
            'u'    => [
2718
                'ú',
2719
                'ù',
2720
                'ủ',
2721
                'ũ',
2722
                'ụ',
2723
                'ư',
2724
                'ứ',
2725
                'ừ',
2726
                'ử',
2727
                'ữ',
2728
                'ự',
2729
                'û',
2730
                'ū',
2731
                'ů',
2732
                'ű',
2733
                'ŭ',
2734
                'ų',
2735
                'µ',
2736
                'у',
2737
                'ဉ',
2738
                'ု',
2739
                'ူ',
2740
                'ǔ',
2741
                'ǖ',
2742
                'ǘ',
2743
                'ǚ',
2744
                'ǜ',
2745
                'უ',
2746
                'उ',
2747
                'u',
2748
                'ў',
2749
                'ü',
2750
            ],
2751
            'v'    => ['в', 'ვ', 'ϐ', 'v'],
2752
            'w'    => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ', 'w'],
2753
            'x'    => ['χ', 'ξ', 'x'],
2754
            'y'    => [
2755
                'ý',
2756
                'ỳ',
2757
                'ỷ',
2758
                'ỹ',
2759
                'ỵ',
2760
                'ÿ',
2761
                'ŷ',
2762
                'й',
2763
                'ы',
2764
                'υ',
2765
                'ϋ',
2766
                'ύ',
2767
                'ΰ',
2768
                'ي',
2769
                'ယ',
2770
                'y',
2771
            ],
2772
            'z'    => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ', 'z'],
2773
            'aa'   => ['ع', 'आ', 'آ'],
2774
            'ae'   => ['æ', 'ǽ'],
2775
            'ai'   => ['ऐ'],
2776
            'ch'   => ['ч', 'ჩ', 'ჭ', 'چ'],
2777
            'dj'   => ['ђ', 'đ'],
2778
            'dz'   => ['џ', 'ძ'],
2779
            'ei'   => ['ऍ'],
2780
            'gh'   => ['غ', 'ღ'],
2781
            'ii'   => ['ई'],
2782
            'ij'   => ['ij'],
2783
            'kh'   => ['х', 'خ', 'ხ'],
2784
            'lj'   => ['љ'],
2785
            'nj'   => ['њ'],
2786
            'oe'   => ['œ', 'ؤ'],
2787
            'oi'   => ['ऑ'],
2788
            'oii'  => ['ऒ'],
2789
            'ps'   => ['ψ'],
2790
            'sh'   => ['ш', 'შ', 'ش'],
2791
            'shch' => ['щ'],
2792
            'ss'   => ['ß'],
2793
            'sx'   => ['ŝ'],
2794
            'th'   => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'],
2795
            'ts'   => ['ц', 'ც', 'წ'],
2796
            'uu'   => ['ऊ'],
2797
            'ya'   => ['я'],
2798
            'yu'   => ['ю'],
2799
            'zh'   => ['ж', 'ჟ', 'ژ'],
2800
            '(c)'  => ['©'],
2801
            'A'    => [
2802
                'Á',
2803
                'À',
2804
                'Ả',
2805
                'Ã',
2806
                'Ạ',
2807
                'Ă',
2808
                'Ắ',
2809
                'Ằ',
2810
                'Ẳ',
2811
                'Ẵ',
2812
                'Ặ',
2813
                'Â',
2814
                'Ấ',
2815
                'Ầ',
2816
                'Ẩ',
2817
                'Ẫ',
2818
                'Ậ',
2819
                'Å',
2820
                'Ā',
2821
                'Ą',
2822
                'Α',
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
                'A',
2849
                'Ä',
2850
            ],
2851
            'B'    => ['Б', 'Β', 'ब', 'B'],
2852
            'C'    => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ', 'C'],
2853
            'D'    => [
2854
                'Ď',
2855
                'Ð',
2856
                'Đ',
2857
                'Ɖ',
2858
                'Ɗ',
2859
                'Ƌ',
2860
                'ᴅ',
2861
                'ᴆ',
2862
                'Д',
2863
                'Δ',
2864
                'D',
2865
            ],
2866
            'E'    => [
2867
                'É',
2868
                'È',
2869
                'Ẻ',
2870
                'Ẽ',
2871
                'Ẹ',
2872
                'Ê',
2873
                'Ế',
2874
                'Ề',
2875
                'Ể',
2876
                'Ễ',
2877
                'Ệ',
2878
                'Ë',
2879
                'Ē',
2880
                'Ę',
2881
                'Ě',
2882
                'Ĕ',
2883
                'Ė',
2884
                'Ε',
2885
                'Έ',
2886
                'Ἐ',
2887
                'Ἑ',
2888
                'Ἒ',
2889
                'Ἓ',
2890
                'Ἔ',
2891
                'Ἕ',
2892
                'Έ',
2893
                'Ὲ',
2894
                'Е',
2895
                'Ё',
2896
                'Э',
2897
                'Є',
2898
                'Ə',
2899
                'E',
2900
            ],
2901
            'F'    => ['Ф', 'Φ', 'F'],
2902
            'G'    => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ', 'G'],
2903
            'H'    => ['Η', 'Ή', 'Ħ', 'H'],
2904
            'I'    => [
2905
                'Í',
2906
                'Ì',
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
                'I',
2936
            ],
2937
            'J'    => ['J'],
2938
            'K'    => ['К', 'Κ', 'K'],
2939
            'L'    => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल', 'L'],
2940
            'M'    => ['М', 'Μ', 'M'],
2941
            'N'    => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν', 'N'],
2942
            'O'    => [
2943
                'Ó',
2944
                'Ò',
2945
                'Ỏ',
2946
                'Õ',
2947
                'Ọ',
2948
                'Ô',
2949
                'Ố',
2950
                'Ồ',
2951
                'Ổ',
2952
                'Ỗ',
2953
                'Ộ',
2954
                'Ơ',
2955
                'Ớ',
2956
                'Ờ',
2957
                'Ở',
2958
                'Ỡ',
2959
                'Ợ',
2960
                'Ø',
2961
                'Ō',
2962
                'Ő',
2963
                'Ŏ',
2964
                'Ο',
2965
                'Ό',
2966
                'Ὀ',
2967
                'Ὁ',
2968
                'Ὂ',
2969
                'Ὃ',
2970
                'Ὄ',
2971
                'Ὅ',
2972
                'Ὸ',
2973
                'Ό',
2974
                'О',
2975
                'Θ',
2976
                'Ө',
2977
                'Ǒ',
2978
                'Ǿ',
2979
                'O',
2980
                'Ö',
2981
            ],
2982
            'P'    => ['П', 'Π', 'P'],
2983
            'Q'    => ['Q'],
2984
            'R'    => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ', 'R'],
2985
            'S'    => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ', 'S'],
2986
            'T'    => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ', 'T'],
2987
            'U'    => [
2988
                'Ú',
2989
                'Ù',
2990
                'Ủ',
2991
                'Ũ',
2992
                'Ụ',
2993
                'Ư',
2994
                'Ứ',
2995
                'Ừ',
2996
                'Ử',
2997
                'Ữ',
2998
                'Ự',
2999
                'Û',
3000
                'Ū',
3001
                'Ů',
3002
                'Ű',
3003
                'Ŭ',
3004
                'Ų',
3005
                'У',
3006
                'Ǔ',
3007
                'Ǖ',
3008
                'Ǘ',
3009
                'Ǚ',
3010
                'Ǜ',
3011
                'U',
3012
                'Ў',
3013
                'Ü',
3014
            ],
3015
            'V'    => ['В', 'V'],
3016
            'W'    => ['Ω', 'Ώ', 'Ŵ', 'W'],
3017
            'X'    => ['Χ', 'Ξ', 'X'],
3018
            'Y'    => [
3019
                'Ý',
3020
                'Ỳ',
3021
                'Ỷ',
3022
                'Ỹ',
3023
                'Ỵ',
3024
                'Ÿ',
3025
                'Ῠ',
3026
                'Ῡ',
3027
                'Ὺ',
3028
                'Ύ',
3029
                'Ы',
3030
                'Й',
3031
                'Υ',
3032
                'Ϋ',
3033
                'Ŷ',
3034
                'Y',
3035
            ],
3036
            'Z'    => ['Ź', 'Ž', 'Ż', 'З', 'Ζ', 'Z'],
3037
            'AE'   => ['Æ', 'Ǽ'],
3038
            'Ch'   => ['Ч'],
3039
            'Dj'   => ['Ђ'],
3040
            'Dz'   => ['Џ'],
3041
            'Gx'   => ['Ĝ'],
3042
            'Hx'   => ['Ĥ'],
3043
            'Ij'   => ['IJ'],
3044
            'Jx'   => ['Ĵ'],
3045
            'Kh'   => ['Х'],
3046
            'Lj'   => ['Љ'],
3047
            'Nj'   => ['Њ'],
3048
            'Oe'   => ['Œ'],
3049
            'Ps'   => ['Ψ'],
3050
            'Sh'   => ['Ш'],
3051
            'Shch' => ['Щ'],
3052
            'Ss'   => ['ẞ'],
3053
            'Th'   => ['Þ'],
3054
            'Ts'   => ['Ц'],
3055
            'Ya'   => ['Я'],
3056
            'Yu'   => ['Ю'],
3057
            'Zh'   => ['Ж'],
3058
            ' '    => [
3059
                "\xC2\xA0",
3060
                "\xE2\x80\x80",
3061
                "\xE2\x80\x81",
3062
                "\xE2\x80\x82",
3063
                "\xE2\x80\x83",
3064
                "\xE2\x80\x84",
3065
                "\xE2\x80\x85",
3066
                "\xE2\x80\x86",
3067
                "\xE2\x80\x87",
3068
                "\xE2\x80\x88",
3069
                "\xE2\x80\x89",
3070
                "\xE2\x80\x8A",
3071
                "\xE2\x80\xAF",
3072
                "\xE2\x81\x9F",
3073
                "\xE3\x80\x80",
3074
                "\xEF\xBE\xA0",
3075
            ],
3076
        ];
3077
    }
3078
3079
    /**
3080
     * Returns true if $str matches the supplied pattern, false otherwise.
3081
     *
3082
     * @param string $pattern <p>Regex pattern to match against.</p>
3083
     *
3084
     * @return bool <p>Whether or not $str matches the pattern.</p>
3085
     */
3086
    protected function matchesPattern(string $pattern): bool
3087
    {
3088
        return $this->utf8::str_matches_pattern($this->str, $pattern);
3089
    }
3090
3091
    /**
3092
     * Returns language-specific replacements for the toAscii() method.
3093
     * For example, German will map 'ä' to 'ae', while other languages
3094
     * will simply return 'a'.
3095
     *
3096
     * @param string $language Language of the source string
3097
     *
3098
     * @return array an array of replacements
3099
     */
3100
    protected static function langSpecificCharsArray(string $language = 'en'): array
3101
    {
3102
        $split = \preg_split('/[-_]/', $language);
3103
        $language = \strtolower($split[0]);
3104
        static $charsArray = [];
3105
3106
        if (isset($charsArray[$language])) {
3107
            return $charsArray[$language];
3108
        }
3109
3110
        $languageSpecific = [
3111
            'de' => [
3112
                ['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü'],
3113
                ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'],
3114
            ],
3115
            'bg' => [
3116
                ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'],
3117
                ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'],
3118
            ],
3119
        ];
3120
3121
        $charsArray[$language] = $languageSpecific[$language] ?? [];
3122
3123
        return $charsArray[$language];
3124
    }
3125
}
3126