Completed
Push — master ( 8af890...b7c649 )
by Lars
06:56
created

Stringy::langSpecificCharsArray()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 25
ccs 9
cts 9
cp 1
crap 2
rs 9.52
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
     * Initializes a Stringy object and assigns both str and encoding properties
34
     * the supplied values. $str is cast to a string prior to assignment, and if
35
     * $encoding is not specified, it defaults to mb_internal_encoding(). Throws
36
     * an InvalidArgumentException if the first argument is an array or object
37
     * without a __toString method.
38
     *
39
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
40
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
41
     *
42
     * @throws \InvalidArgumentException <p>if an array or object without a
43
     *                                   __toString method is passed as the first argument</p>
44
     */
45 2105
    public function __construct($str = '', string $encoding = null)
46
    {
47 2105
        if (\is_array($str)) {
48 2
            throw new \InvalidArgumentException(
49 2
                'Passed value cannot be an array'
50
            );
51
        }
52
53
        if (
54 2103
            \is_object($str)
55
            &&
56 2103
            !\method_exists($str, '__toString')
57
        ) {
58 2
            throw new \InvalidArgumentException(
59 2
                'Passed object must have a __toString method'
60
            );
61
        }
62
63 2101
        $this->str = (string) $str;
64
65 2101
        if ($encoding && $encoding !== 'UTF-8') {
0 ignored issues
show
Bug Best Practice introduced by
The expression $encoding of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
66
            $this->encoding = UTF8::normalize_encoding($encoding);
67
        } else {
68 2101
            $this->encoding = 'UTF-8';
69
        }
70 2101
    }
71
72
    /**
73
     * Returns the value in $str.
74
     *
75
     * @return string <p>The current value of the $str property.</p>
76
     */
77 978
    public function __toString()
78
    {
79 978
        return (string) $this->str;
80
    }
81
82
    /**
83
     * Gets the substring after the first occurrence of a separator.
84
     * If no match is found returns new empty Stringy object.
85
     *
86
     * @param string $separator
87
     *
88
     * @return static
89
     */
90 2
    public function afterFirst(string $separator): self
91
    {
92 2
        return static::create(
93 2
            UTF8::str_substr_after_first_separator(
94 2
                $this->str,
95 2
                $separator,
96 2
                $this->encoding
97
            )
98
        );
99
    }
100
101
    /**
102
     * Gets the substring after the first occurrence of a separator.
103
     * If no match is found returns new empty Stringy object.
104
     *
105
     * @param string $separator
106
     *
107
     * @return static
108
     */
109 1
    public function afterFirstIgnoreCase(string $separator): self
110
    {
111 1
        return static::create(
112 1
            UTF8::str_isubstr_after_first_separator(
113 1
                $this->str,
114 1
                $separator,
115 1
                $this->encoding
116
            )
117
        );
118
    }
119
120
    /**
121
     * Gets the substring after the last occurrence of a separator.
122
     * If no match is found returns new empty Stringy object.
123
     *
124
     * @param string $separator
125
     *
126
     * @return static
127
     */
128 1
    public function afterLast(string $separator): self
129
    {
130 1
        return static::create(
131 1
            UTF8::str_substr_after_last_separator(
132 1
                $this->str,
133 1
                $separator,
134 1
                $this->encoding
135
            )
136
        );
137
    }
138
139
    /**
140
     * Gets the substring after the last occurrence of a separator.
141
     * If no match is found returns new empty Stringy object.
142
     *
143
     * @param string $separator
144
     *
145
     * @return static
146
     */
147 1
    public function afterLastIgnoreCase(string $separator): self
148
    {
149 1
        return static::create(
150 1
            UTF8::str_isubstr_after_last_separator(
151 1
                $this->str,
152 1
                $separator,
153 1
                $this->encoding
154
            )
155
        );
156
    }
157
158
    /**
159
     * Returns a new string with $string appended.
160
     *
161
     * @param string $string <p>The string to append.</p>
162
     *
163
     * @return static <p>Object with appended $string.</p>
164
     */
165 7
    public function append(string $string): self
166
    {
167 7
        return static::create($this->str . $string, $this->encoding);
168
    }
169
170
    /**
171
     * Append an password (limited to chars that are good readable).
172
     *
173
     * @param int $length <p>Length of the random string.</p>
174
     *
175
     * @return static <p>Object with appended password.</p>
176
     */
177 1
    public function appendPassword(int $length): self
178
    {
179 1
        $possibleChars = '2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ!?_#';
180
181 1
        return $this->appendRandomString($length, $possibleChars);
182
    }
183
184
    /**
185
     * Append an random string.
186
     *
187
     * @param int    $length        <p>Length of the random string.</p>
188
     * @param string $possibleChars [optional] <p>Characters string for the random selection.</p>
189
     *
190
     * @return static <p>Object with appended random string.</p>
191
     */
192 2
    public function appendRandomString(int $length, string $possibleChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'): self
193
    {
194 2
        $str = UTF8::get_random_string($length, $possibleChars);
195
196 2
        return $this->append($str);
197
    }
198
199
    /**
200
     * Append an unique identifier.
201
     *
202
     * @param int|string $entropyExtra [optional] <p>Extra entropy via a string or int value.</p>
203
     * @param bool       $md5          [optional] <p>Return the unique identifier as md5-hash? Default: true</p>
204
     *
205
     * @return static <p>Object with appended unique identifier as md5-hash.</p>
206
     */
207 1
    public function appendUniqueIdentifier($entropyExtra = '', bool $md5 = true): self
208
    {
209 1
        $uniqueString = UTF8::get_unique_string($entropyExtra, $md5);
210
211 1
        return $this->append($uniqueString);
212
    }
213
214
    /**
215
     * Returns the character at $index, with indexes starting at 0.
216
     *
217
     * @param int $index <p>Position of the character.</p>
218
     *
219
     * @return static <p>The character at $index.</p>
220
     */
221 16
    public function at(int $index): self
222
    {
223 16
        $chr = UTF8::char_at($this->str, $index);
224
225 16
        return static::create($chr, $this->encoding);
226
    }
227
228
    /**
229
     * Gets the substring before the first occurrence of a separator.
230
     * If no match is found returns new empty Stringy object.
231
     *
232
     * @param string $separator
233
     *
234
     * @return static
235
     */
236 1
    public function beforeFirst(string $separator): self
237
    {
238 1
        return static::create(
239 1
            UTF8::str_substr_before_first_separator(
240 1
                $this->str,
241 1
                $separator,
242 1
                $this->encoding
243
            )
244
        );
245
    }
246
247
    /**
248
     * Gets the substring before the first occurrence of a separator.
249
     * If no match is found returns new empty Stringy object.
250
     *
251
     * @param string $separator
252
     *
253
     * @return static
254
     */
255 1
    public function beforeFirstIgnoreCase(string $separator): self
256
    {
257 1
        return static::create(
258 1
            UTF8::str_isubstr_before_first_separator(
259 1
                $this->str,
260 1
                $separator,
261 1
                $this->encoding
262
            )
263
        );
264
    }
265
266
    /**
267
     * Gets the substring before the last occurrence of a separator.
268
     * If no match is found returns new empty Stringy object.
269
     *
270
     * @param string $separator
271
     *
272
     * @return static
273
     */
274 1
    public function beforeLast(string $separator): self
275
    {
276 1
        return static::create(
277 1
            UTF8::str_substr_before_last_separator(
278 1
                $this->str,
279 1
                $separator,
280 1
                $this->encoding
281
            )
282
        );
283
    }
284
285
    /**
286
     * Gets the substring before the last occurrence of a separator.
287
     * If no match is found returns new empty Stringy object.
288
     *
289
     * @param string $separator
290
     *
291
     * @return static
292
     */
293 1
    public function beforeLastIgnoreCase(string $separator): self
294
    {
295 1
        return static::create(
296 1
            UTF8::str_isubstr_before_last_separator(
297 1
                $this->str,
298 1
                $separator,
299 1
                $this->encoding
300
            )
301
        );
302
    }
303
304
    /**
305
     * Returns the substring between $start and $end, if found, or an empty
306
     * string. An optional offset may be supplied from which to begin the
307
     * search for the start string.
308
     *
309
     * @param string $start  <p>Delimiter marking the start of the substring.</p>
310
     * @param string $end    <p>Delimiter marking the end of the substring.</p>
311
     * @param int    $offset [optional] <p>Index from which to begin the search. Default: 0</p>
312
     *
313
     * @return static <p>Object whose $str is a substring between $start and $end.</p>
314
     */
315 32
    public function between(string $start, string $end, int $offset = null): self
316
    {
317 32
        $str = UTF8::between(
318 32
            $this->str,
319 32
            $start,
320 32
            $end,
321 32
            (int) $offset,
322 32
            $this->encoding
323
        );
324
325 32
        return static::create($str, $this->encoding);
326
    }
327
328
    /**
329
     * Returns a camelCase version of the string. Trims surrounding spaces,
330
     * capitalizes letters following digits, spaces, dashes and underscores,
331
     * and removes spaces, dashes, as well as underscores.
332
     *
333
     * @return static <p>Object with $str in camelCase.</p>
334
     */
335 38
    public function camelize(): self
336
    {
337 38
        return static::create(
338 38
            UTF8::str_camelize($this->str, $this->encoding),
339 38
            $this->encoding
340
        );
341
    }
342
343
    /**
344
     * Returns the string with the first letter of each word capitalized,
345
     * except for when the word is a name which shouldn't be capitalized.
346
     *
347
     * @return static <p>Object with $str capitalized.</p>
348
     */
349 39
    public function capitalizePersonalName(): self
350
    {
351 39
        return static::create(
352 39
            UTF8::str_capitalize_name($this->str),
353 39
            $this->encoding
354
        );
355
    }
356
357
    /**
358
     * Returns an array consisting of the characters in the string.
359
     *
360
     * @return array <p>An array of string chars.</p>
361
     */
362 8
    public function chars(): array
363
    {
364 8
        return UTF8::chars($this->str);
365
    }
366
367
    /**
368
     * Trims the string and replaces consecutive whitespace characters with a
369
     * single space. This includes tabs and newline characters, as well as
370
     * multibyte whitespace such as the thin space and ideographic space.
371
     *
372
     * @return static <p>Object with a trimmed $str and condensed whitespace.</p>
373
     */
374 26
    public function collapseWhitespace(): self
375
    {
376 26
        $str = UTF8::collapse_whitespace($this->str);
377
378 26
        return static::create($str, $this->encoding);
379
    }
380
381
    /**
382
     * Returns true if the string contains $needle, false otherwise. By default
383
     * the comparison is case-sensitive, but can be made insensitive by setting
384
     * $caseSensitive to false.
385
     *
386
     * @param string $needle        <p>Substring to look for.</p>
387
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
388
     *
389
     * @return bool <p>Whether or not $str contains $needle.</p>
390
     */
391 42
    public function contains(string $needle, bool $caseSensitive = true): bool
392
    {
393 42
        return UTF8::str_contains(
394 42
            $this->str,
395 42
            $needle,
396 42
            $caseSensitive,
397 42
            $this->encoding
398
        );
399
    }
400
401
    /**
402
     * Returns true if the string contains all $needles, false otherwise. By
403
     * default the comparison is case-sensitive, but can be made insensitive by
404
     * setting $caseSensitive to false.
405
     *
406
     * @param array $needles       <p>SubStrings to look for.</p>
407
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
408
     *
409
     * @return bool <p>Whether or not $str contains $needle.</p>
410
     */
411 87
    public function containsAll(array $needles, bool $caseSensitive = true): bool
412
    {
413 87
        return UTF8::str_contains_all(
414 87
            $this->str,
415 87
            $needles,
416 87
            $caseSensitive,
417 87
            $this->encoding
418
        );
419
    }
420
421
    /**
422
     * Returns true if the string contains any $needles, false otherwise. By
423
     * default the comparison is case-sensitive, but can be made insensitive by
424
     * setting $caseSensitive to false.
425
     *
426
     * @param array $needles       <p>SubStrings to look for.</p>
427
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
428
     *
429
     * @return bool <p>Whether or not $str contains $needle.</p>
430
     */
431 86
    public function containsAny(array $needles, bool $caseSensitive = true): bool
432
    {
433 86
        return UTF8::str_contains_any(
434 86
            $this->str,
435 86
            $needles,
436 86
            $caseSensitive,
437 86
            $this->encoding
438
        );
439
    }
440
441
    /**
442
     * Returns the length of the string, implementing the countable interface.
443
     *
444
     * @return int <p>The number of characters in the string, given the encoding.</p>
445
     */
446 2
    public function count(): int
447
    {
448 2
        return $this->length();
449
    }
450
451
    /**
452
     * Returns the number of occurrences of $substring in the given string.
453
     * By default, the comparison is case-sensitive, but can be made insensitive
454
     * by setting $caseSensitive to false.
455
     *
456
     * @param string $substring     <p>The substring to search for.</p>
457
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
458
     *
459
     * @return false|int <p>This functions returns an integer or false if there isn't a string.</p>
460
     */
461 30
    public function countSubstr(string $substring, bool $caseSensitive = true)
462
    {
463 30
        return UTF8::substr_count_simple(
464 30
            $this->str,
465 30
            $substring,
466 30
            $caseSensitive,
467 30
            $this->encoding
468
        );
469
    }
470
471
    /**
472
     * Creates a Stringy object and assigns both str and encoding properties
473
     * the supplied values. $str is cast to a string prior to assignment, and if
474
     * $encoding is not specified, it defaults to mb_internal_encoding(). It
475
     * then returns the initialized object. Throws an InvalidArgumentException
476
     * if the first argument is an array or object without a __toString method.
477
     *
478
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
479
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
480
     *
481
     * @throws \InvalidArgumentException <p>if an array or object without a
482
     *                                   __toString method is passed as the first argument</p>
483
     *
484
     * @return static <p>A Stringy object.</p>
485
     */
486 2085
    public static function create($str = '', string $encoding = null): self
487
    {
488 2085
        if ($encoding && $encoding !== 'UTF-8') {
0 ignored issues
show
Bug Best Practice introduced by
The expression $encoding of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
489
            $encoding = UTF8::normalize_encoding($encoding);
490
        } else {
491 2085
            $encoding = 'UTF-8';
492
        }
493
494 2085
        return new static($str, $encoding);
495
    }
496
497
    /**
498
     * Returns a lowercase and trimmed string separated by dashes. Dashes are
499
     * inserted before uppercase characters (with the exception of the first
500
     * character of the string), and in place of spaces as well as underscores.
501
     *
502
     * @return static <p>Object with a dasherized $str</p>
503
     */
504 38
    public function dasherize(): self
505
    {
506 38
        $str = UTF8::str_dasherize($this->str);
507
508 38
        return static::create($str, $this->encoding);
509
    }
510
511
    /**
512
     * Returns a lowercase and trimmed string separated by the given delimiter.
513
     * Delimiters are inserted before uppercase characters (with the exception
514
     * of the first character of the string), and in place of spaces, dashes,
515
     * and underscores. Alpha delimiters are not converted to lowercase.
516
     *
517
     * @param string $delimiter <p>Sequence used to separate parts of the string.</p>
518
     *
519
     * @return static <p>Object with a delimited $str.</p>
520
     */
521 76
    public function delimit(string $delimiter): self
522
    {
523 76
        $str = UTF8::str_delimit($this->str, $delimiter);
524
525 76
        return static::create($str, $this->encoding);
526
    }
527
528
    /**
529
     * Returns true if the string ends with $substring, false otherwise. By
530
     * default, the comparison is case-sensitive, but can be made insensitive
531
     * by setting $caseSensitive to false.
532
     *
533
     * @param string $substring     <p>The substring to look for.</p>
534
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
535
     *
536
     * @return bool <p>Whether or not $str ends with $substring.</p>
537
     */
538 22
    public function endsWith(string $substring, bool $caseSensitive = true): bool
539
    {
540 22
        if ($caseSensitive) {
541 14
            return UTF8::str_ends_with($this->str, $substring);
542
        }
543
544 8
        return UTF8::str_iends_with($this->str, $substring);
545
    }
546
547
    /**
548
     * Returns true if the string ends with any of $substrings, false otherwise.
549
     * By default, the comparison is case-sensitive, but can be made insensitive
550
     * by setting $caseSensitive to false.
551
     *
552
     * @param string[] $substrings    <p>Substrings to look for.</p>
553
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
554
     *
555
     * @return bool <p>Whether or not $str ends with $substring.</p>
556
     */
557 22
    public function endsWithAny(array $substrings, bool $caseSensitive = true): bool
558
    {
559 22
        if ($caseSensitive) {
560 14
            return UTF8::str_ends_with_any($this->str, $substrings);
561
        }
562
563 8
        return UTF8::str_iends_with_any($this->str, $substrings);
564
    }
565
566
    /**
567
     * Ensures that the string begins with $substring. If it doesn't, it's
568
     * prepended.
569
     *
570
     * @param string $substring <p>The substring to add if not present.</p>
571
     *
572
     * @return static <p>Object with its $str prefixed by the $substring.</p>
573
     */
574 20
    public function ensureLeft(string $substring): self
575
    {
576 20
        $str = UTF8::str_ensure_left($this->str, $substring);
577
578 20
        return static::create($str, $this->encoding);
579
    }
580
581
    /**
582
     * Ensures that the string ends with $substring. If it doesn't, it's appended.
583
     *
584
     * @param string $substring <p>The substring to add if not present.</p>
585
     *
586
     * @return static <p>Object with its $str suffixed by the $substring.</p>
587
     */
588 20
    public function ensureRight(string $substring): self
589
    {
590 20
        $str = UTF8::str_ensure_right($this->str, $substring);
591
592 20
        return static::create($str, $this->encoding);
593
    }
594
595
    /**
596
     * Create a escape html version of the string via "UTF8::htmlspecialchars()".
597
     *
598
     * @return static
599
     */
600 6
    public function escape(): self
601
    {
602 6
        $str = UTF8::htmlspecialchars(
603 6
            $this->str,
604 6
            \ENT_QUOTES | \ENT_SUBSTITUTE,
605 6
            $this->encoding
606
        );
607
608 6
        return static::create($str, $this->encoding);
609
    }
610
611
    /**
612
     * Create an extract from a sentence, so if the search-string was found, it try to centered in the output.
613
     *
614
     * @param string   $search
615
     * @param int|null $length                 [optional] <p>Default: null === text->length / 2</p>
616
     * @param string   $replacerForSkippedText [optional] <p>Default: …</p>
617
     *
618
     * @return static
619
     */
620 1
    public function extractText(string $search = '', int $length = null, string $replacerForSkippedText = '…'): self
621
    {
622 1
        $extract = UTF8::extract_text(
623 1
            $this->str,
624 1
            $search,
625 1
            $length,
626 1
            $replacerForSkippedText,
627 1
            $this->encoding
628
        );
629
630 1
        return static::create($extract, $this->encoding);
631
    }
632
633
    /**
634
     * Returns the first $n characters of the string.
635
     *
636
     * @param int $n <p>Number of characters to retrieve from the start.</p>
637
     *
638
     * @return static <p>Object with its $str being the first $n chars.</p>
639
     */
640 25
    public function first(int $n): self
641
    {
642 25
        $str = UTF8::first_char($this->str, $n);
643
644 25
        return static::create($str, $this->encoding);
645
    }
646
647
    /**
648
     * Returns the encoding used by the Stringy object.
649
     *
650
     * @return string <p>The current value of the $encoding property.</p>
651
     */
652 5
    public function getEncoding(): string
653
    {
654 5
        return $this->encoding;
655
    }
656
657
    /**
658
     * Returns a new ArrayIterator, thus implementing the IteratorAggregate
659
     * interface. The ArrayIterator's constructor is passed an array of chars
660
     * in the multibyte string. This enables the use of foreach with instances
661
     * of Stringy\Stringy.
662
     *
663
     * @return \ArrayIterator <p>An iterator for the characters in the string.</p>
664
     */
665 2
    public function getIterator(): \ArrayIterator
666
    {
667 2
        return new \ArrayIterator($this->chars());
668
    }
669
670
    /**
671
     * Returns true if the string contains a lower case char, false otherwise.
672
     *
673
     * @return bool <p>Whether or not the string contains a lower case character.</p>
674
     */
675 24
    public function hasLowerCase(): bool
676
    {
677 24
        return UTF8::has_lowercase($this->str);
678
    }
679
680
    /**
681
     * Returns true if the string contains an upper case char, false otherwise.
682
     *
683
     * @return bool <p>Whether or not the string contains an upper case character.</p>
684
     */
685 24
    public function hasUpperCase(): bool
686
    {
687 24
        return UTF8::has_uppercase($this->str);
688
    }
689
690
    /**
691
     * Convert all HTML entities to their applicable characters.
692
     *
693
     * @param int $flags [optional] <p>
694
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
695
     *                   which document type to use. The default is ENT_COMPAT.
696
     *                   <table>
697
     *                   Available <i>flags</i> constants
698
     *                   <tr valign="top">
699
     *                   <td>Constant Name</td>
700
     *                   <td>Description</td>
701
     *                   </tr>
702
     *                   <tr valign="top">
703
     *                   <td><b>ENT_COMPAT</b></td>
704
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
705
     *                   </tr>
706
     *                   <tr valign="top">
707
     *                   <td><b>ENT_QUOTES</b></td>
708
     *                   <td>Will convert both double and single quotes.</td>
709
     *                   </tr>
710
     *                   <tr valign="top">
711
     *                   <td><b>ENT_NOQUOTES</b></td>
712
     *                   <td>Will leave both double and single quotes unconverted.</td>
713
     *                   </tr>
714
     *                   <tr valign="top">
715
     *                   <td><b>ENT_HTML401</b></td>
716
     *                   <td>
717
     *                   Handle code as HTML 4.01.
718
     *                   </td>
719
     *                   </tr>
720
     *                   <tr valign="top">
721
     *                   <td><b>ENT_XML1</b></td>
722
     *                   <td>
723
     *                   Handle code as XML 1.
724
     *                   </td>
725
     *                   </tr>
726
     *                   <tr valign="top">
727
     *                   <td><b>ENT_XHTML</b></td>
728
     *                   <td>
729
     *                   Handle code as XHTML.
730
     *                   </td>
731
     *                   </tr>
732
     *                   <tr valign="top">
733
     *                   <td><b>ENT_HTML5</b></td>
734
     *                   <td>
735
     *                   Handle code as HTML 5.
736
     *                   </td>
737
     *                   </tr>
738
     *                   </table>
739
     *                   </p>
740
     *
741
     * @return static <p>Object with the resulting $str after being html decoded.</p>
742
     */
743 10 View Code Duplication
    public function htmlDecode(int $flags = \ENT_COMPAT): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
744
    {
745 10
        $str = UTF8::html_entity_decode(
746 10
            $this->str,
747 10
            $flags,
748 10
            $this->encoding
749
        );
750
751 10
        return static::create($str, $this->encoding);
752
    }
753
754
    /**
755
     * Convert all applicable characters to HTML entities.
756
     *
757
     * @param int $flags [optional] <p>
758
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
759
     *                   which document type to use. The default is ENT_COMPAT.
760
     *                   <table>
761
     *                   Available <i>flags</i> constants
762
     *                   <tr valign="top">
763
     *                   <td>Constant Name</td>
764
     *                   <td>Description</td>
765
     *                   </tr>
766
     *                   <tr valign="top">
767
     *                   <td><b>ENT_COMPAT</b></td>
768
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
769
     *                   </tr>
770
     *                   <tr valign="top">
771
     *                   <td><b>ENT_QUOTES</b></td>
772
     *                   <td>Will convert both double and single quotes.</td>
773
     *                   </tr>
774
     *                   <tr valign="top">
775
     *                   <td><b>ENT_NOQUOTES</b></td>
776
     *                   <td>Will leave both double and single quotes unconverted.</td>
777
     *                   </tr>
778
     *                   <tr valign="top">
779
     *                   <td><b>ENT_HTML401</b></td>
780
     *                   <td>
781
     *                   Handle code as HTML 4.01.
782
     *                   </td>
783
     *                   </tr>
784
     *                   <tr valign="top">
785
     *                   <td><b>ENT_XML1</b></td>
786
     *                   <td>
787
     *                   Handle code as XML 1.
788
     *                   </td>
789
     *                   </tr>
790
     *                   <tr valign="top">
791
     *                   <td><b>ENT_XHTML</b></td>
792
     *                   <td>
793
     *                   Handle code as XHTML.
794
     *                   </td>
795
     *                   </tr>
796
     *                   <tr valign="top">
797
     *                   <td><b>ENT_HTML5</b></td>
798
     *                   <td>
799
     *                   Handle code as HTML 5.
800
     *                   </td>
801
     *                   </tr>
802
     *                   </table>
803
     *                   </p>
804
     *
805
     * @return static <p>Object with the resulting $str after being html encoded.</p>
806
     */
807 10 View Code Duplication
    public function htmlEncode(int $flags = \ENT_COMPAT): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
808
    {
809 10
        $str = UTF8::htmlentities(
810 10
            $this->str,
811 10
            $flags,
812 10
            $this->encoding
813
        );
814
815 10
        return static::create($str, $this->encoding);
816
    }
817
818
    /**
819
     * Capitalizes the first word of the string, replaces underscores with
820
     * spaces, and strips '_id'.
821
     *
822
     * @return static <p>Object with a humanized $str.</p>
823
     */
824 6
    public function humanize(): self
825
    {
826 6
        $str = UTF8::str_humanize($this->str);
827
828 6
        return static::create($str, $this->encoding);
829
    }
830
831
    /**
832
     * Returns the index of the first occurrence of $needle in the string,
833
     * and false if not found. Accepts an optional offset from which to begin
834
     * the search.
835
     *
836
     * @param string $needle <p>Substring to look for.</p>
837
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
838
     *
839
     * @return false|int <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
840
     */
841 20
    public function indexOf(string $needle, int $offset = 0)
842
    {
843 20
        return UTF8::strpos(
844 20
            $this->str,
845 20
            $needle,
846 20
            $offset,
847 20
            $this->encoding
848
        );
849
    }
850
851
    /**
852
     * Returns the index of the first occurrence of $needle in the string,
853
     * and false if not found. Accepts an optional offset from which to begin
854
     * the search.
855
     *
856
     * @param string $needle <p>Substring to look for.</p>
857
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
858
     *
859
     * @return false|int <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
860
     */
861
    public function indexOfIgnoreCase(string $needle, int $offset = 0)
862
    {
863
        return UTF8::stripos(
864
            $this->str,
865
            $needle,
866
            $offset,
867
            $this->encoding
868
        );
869
    }
870
871
    /**
872
     * Returns the index of the last occurrence of $needle in the string,
873
     * and false if not found. Accepts an optional offset from which to begin
874
     * the search. Offsets may be negative to count from the last character
875
     * in the string.
876
     *
877
     * @param string $needle <p>Substring to look for.</p>
878
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
879
     *
880
     * @return false|int <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
881
     */
882 20
    public function indexOfLast(string $needle, int $offset = 0)
883
    {
884 20
        return UTF8::strrpos(
885 20
            $this->str,
886 20
            $needle,
887 20
            $offset,
888 20
            $this->encoding
889
        );
890
    }
891
892
    /**
893
     * Returns the index of the last occurrence of $needle in the string,
894
     * and false if not found. Accepts an optional offset from which to begin
895
     * the search. Offsets may be negative to count from the last character
896
     * in the string.
897
     *
898
     * @param string $needle <p>Substring to look for.</p>
899
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
900
     *
901
     * @return false|int <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
902
     */
903
    public function indexOfLastIgnoreCase(string $needle, int $offset = 0)
904
    {
905
        return UTF8::strripos(
906
            $this->str,
907
            $needle,
908
            $offset,
909
            $this->encoding
910
        );
911
    }
912
913
    /**
914
     * Inserts $substring into the string at the $index provided.
915
     *
916
     * @param string $substring <p>String to be inserted.</p>
917
     * @param int    $index     <p>The index at which to insert the substring.</p>
918
     *
919
     * @return static <p>Object with the resulting $str after the insertion.</p>
920
     */
921 16
    public function insert(string $substring, int $index): self
922
    {
923 16
        $str = UTF8::str_insert(
924 16
            $this->str,
925 16
            $substring,
926 16
            $index,
927 16
            $this->encoding
928
        );
929
930 16
        return static::create($str, $this->encoding);
931
    }
932
933
    /**
934
     * Returns true if the string contains the $pattern, otherwise false.
935
     *
936
     * WARNING: Asterisks ("*") are translated into (".*") zero-or-more regular
937
     * expression wildcards.
938
     *
939
     * @credit Originally from Laravel, thanks Taylor.
940
     *
941
     * @param string $pattern <p>The string or pattern to match against.</p>
942
     *
943
     * @return bool <p>Whether or not we match the provided pattern.</p>
944
     */
945 13
    public function is(string $pattern): bool
946
    {
947 13
        if ($this->toString() === $pattern) {
948 1
            return true;
949
        }
950
951 12
        $quotedPattern = \preg_quote($pattern, '/');
952 12
        $replaceWildCards = \str_replace('\*', '.*', $quotedPattern);
953
954 12
        return $this->matchesPattern('^' . $replaceWildCards . '\z');
955
    }
956
957
    /**
958
     * Returns true if the string contains only alphabetic chars, false otherwise.
959
     *
960
     * @return bool <p>Whether or not $str contains only alphabetic chars.</p>
961
     */
962 20
    public function isAlpha(): bool
963
    {
964 20
        return UTF8::is_alpha($this->str);
965
    }
966
967
    /**
968
     * Returns true if the string contains only alphabetic and numeric chars, false otherwise.
969
     *
970
     * @return bool <p>Whether or not $str contains only alphanumeric chars.</p>
971
     */
972 26
    public function isAlphanumeric(): bool
973
    {
974 26
        return UTF8::is_alphanumeric($this->str);
975
    }
976
977
    /**
978
     * Returns true if the string is base64 encoded, false otherwise.
979
     *
980
     * @param bool $emptyStringIsValid
981
     *
982
     * @return bool <p>Whether or not $str is base64 encoded.</p>
983
     */
984 14
    public function isBase64($emptyStringIsValid = true): bool
985
    {
986 14
        return UTF8::is_base64($this->str, $emptyStringIsValid);
987
    }
988
989
    /**
990
     * Returns true if the string contains only whitespace chars, false otherwise.
991
     *
992
     * @return bool <p>Whether or not $str contains only whitespace characters.</p>
993
     */
994 30
    public function isBlank(): bool
995
    {
996 30
        return UTF8::is_blank($this->str);
997
    }
998
999
    /**
1000
     * Returns true if the string contains a valid E-Mail address, false otherwise.
1001
     *
1002
     * @param bool $useExampleDomainCheck   [optional] <p>Default: false</p>
1003
     * @param bool $useTypoInDomainCheck    [optional] <p>Default: false</p>
1004
     * @param bool $useTemporaryDomainCheck [optional] <p>Default: false</p>
1005
     * @param bool $useDnsCheck             [optional] <p>Default: false</p>
1006
     *
1007
     * @return bool <p>Whether or not $str contains a valid E-Mail address.</p>
1008
     */
1009 1
    public function isEmail(bool $useExampleDomainCheck = false, bool $useTypoInDomainCheck = false, bool $useTemporaryDomainCheck = false, bool $useDnsCheck = false): bool
1010
    {
1011 1
        return EmailCheck::isValid($this->str, $useExampleDomainCheck, $useTypoInDomainCheck, $useTemporaryDomainCheck, $useDnsCheck);
1012
    }
1013
1014
    /**
1015
     * Determine whether the string is considered to be empty.
1016
     *
1017
     * A variable is considered empty if it does not exist or if its value equals FALSE.
1018
     * empty() does not generate a warning if the variable does not exist.
1019
     *
1020
     * @return bool <p>Whether or not $str is empty().</p>
1021
     */
1022
    public function isEmpty(): bool
1023
    {
1024
        return UTF8::is_empty($this->str);
1025
    }
1026
1027
    /**
1028
     * Returns true if the string contains only hexadecimal chars, false otherwise.
1029
     *
1030
     * @return bool <p>Whether or not $str contains only hexadecimal chars.</p>
1031
     */
1032 26
    public function isHexadecimal(): bool
1033
    {
1034 26
        return UTF8::is_hexadecimal($this->str);
1035
    }
1036
1037
    /**
1038
     * Returns true if the string contains HTML-Tags, false otherwise.
1039
     *
1040
     * @return bool <p>Whether or not $str contains HTML-Tags.</p>
1041
     */
1042 1
    public function isHtml(): bool
1043
    {
1044 1
        return UTF8::is_html($this->str);
1045
    }
1046
1047
    /**
1048
     * Returns true if the string is JSON, false otherwise. Unlike json_decode
1049
     * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
1050
     * in that an empty string is not considered valid JSON.
1051
     *
1052
     * @param bool $onlyArrayOrObjectResultsAreValid
1053
     *
1054
     * @return bool <p>Whether or not $str is JSON.</p>
1055
     */
1056 40
    public function isJson($onlyArrayOrObjectResultsAreValid = false): bool
1057
    {
1058 40
        return UTF8::is_json($this->str, $onlyArrayOrObjectResultsAreValid);
1059
    }
1060
1061
    /**
1062
     * Returns true if the string contains only lower case chars, false otherwise.
1063
     *
1064
     * @return bool <p>Whether or not $str contains only lower case characters.</p>
1065
     */
1066 16
    public function isLowerCase(): bool
1067
    {
1068 16
        return UTF8::is_lowercase($this->str);
1069
    }
1070
1071
    /**
1072
     * Returns true if the string is serialized, false otherwise.
1073
     *
1074
     * @return bool <p>Whether or not $str is serialized.</p>
1075
     */
1076 14
    public function isSerialized(): bool
1077
    {
1078 14
        return UTF8::is_serialized($this->str);
1079
    }
1080
1081
    /**
1082
     * Returns true if the string contains only lower case chars, false
1083
     * otherwise.
1084
     *
1085
     * @return bool <p>Whether or not $str contains only lower case characters.</p>
1086
     */
1087 16
    public function isUpperCase(): bool
1088
    {
1089 16
        return UTF8::is_uppercase($this->str);
1090
    }
1091
1092
    /**
1093
     * Returns the last $n characters of the string.
1094
     *
1095
     * @param int $n <p>Number of characters to retrieve from the end.</p>
1096
     *
1097
     * @return static <p>Object with its $str being the last $n chars.</p>
1098
     */
1099 24
    public function last(int $n): self
1100
    {
1101 24
        $str = UTF8::str_last_char(
1102 24
            $this->str,
1103 24
            $n,
1104 24
            $this->encoding
1105
        );
1106
1107 24
        return static::create($str, $this->encoding);
1108
    }
1109
1110
    /**
1111
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
1112
     * If no match is found returns new empty Stringy object.
1113
     *
1114
     * @param string $needle       <p>The string to look for.</p>
1115
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
1116
     *
1117
     * @return static
1118
     */
1119 2
    public function lastSubstringOf(string $needle, bool $beforeNeedle = false): self
1120
    {
1121 2
        $str = UTF8::str_substr_last($this->str, $needle, $beforeNeedle, $this->encoding);
1122
1123 2
        return static::create($str, $this->encoding);
1124
    }
1125
1126
    /**
1127
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
1128
     * If no match is found returns new empty Stringy object.
1129
     *
1130
     * @param string $needle       <p>The string to look for.</p>
1131
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
1132
     *
1133
     * @return static
1134
     */
1135 1
    public function lastSubstringOfIgnoreCase(string $needle, bool $beforeNeedle = false): self
1136
    {
1137 1
        $str = UTF8::str_isubstr_last($this->str, $needle, $beforeNeedle, $this->encoding);
1138
1139 1
        return static::create($str, $this->encoding);
1140
    }
1141
1142
    /**
1143
     * Returns the length of the string.
1144
     *
1145
     * @return int <p>The number of characters in $str given the encoding.</p>
1146
     */
1147 11
    public function length(): int
1148
    {
1149 11
        return UTF8::strlen($this->str, $this->encoding);
1150
    }
1151
1152
    /**
1153
     * Line-Wrap the string after $limit, but also after the next word.
1154
     *
1155
     * @param int $limit
1156
     *
1157
     * @return static
1158
     */
1159 1
    public function lineWrapAfterWord(int $limit): self
1160
    {
1161 1
        $str = UTF8::wordwrap_per_line($this->str, $limit);
1162
1163 1
        return static::create($str, $this->encoding);
1164
    }
1165
1166
    /**
1167
     * Splits on newlines and carriage returns, returning an array of Stringy
1168
     * objects corresponding to the lines in the string.
1169
     *
1170
     * @return static[] <p>An array of Stringy objects.</p>
1171
     */
1172 32
    public function lines(): array
1173
    {
1174 32
        $array = UTF8::str_to_lines($this->str);
1175
1176 32
        foreach ($array as $i => &$value) {
1177 32
            $value = static::create($value, $this->encoding);
1178
        }
1179
1180 32
        return $array;
1181
    }
1182
1183
    /**
1184
     * Returns the longest common prefix between the string and $otherStr.
1185
     *
1186
     * @param string $otherStr <p>Second string for comparison.</p>
1187
     *
1188
     * @return static <p>Object with its $str being the longest common prefix.</p>
1189
     */
1190 20
    public function longestCommonPrefix(string $otherStr): self
1191
    {
1192 20
        $str = UTF8::str_longest_common_prefix(
1193 20
            $this->str,
1194 20
            $otherStr,
1195 20
            $this->encoding
1196
        );
1197
1198 20
        return static::create($str, $this->encoding);
1199
    }
1200
1201
    /**
1202
     * Returns the longest common substring between the string and $otherStr.
1203
     * In the case of ties, it returns that which occurs first.
1204
     *
1205
     * @param string $otherStr <p>Second string for comparison.</p>
1206
     *
1207
     * @return static <p>Object with its $str being the longest common substring.</p>
1208
     */
1209 20
    public function longestCommonSubstring(string $otherStr): self
1210
    {
1211 20
        $longestCommonSubstring = UTF8::str_longest_common_substring(
1212 20
            $this->str,
1213 20
            $otherStr,
1214 20
            $this->encoding
1215
        );
1216
1217 20
        return static::create($longestCommonSubstring, $this->encoding);
1218
    }
1219
1220
    /**
1221
     * Returns the longest common suffix between the string and $otherStr.
1222
     *
1223
     * @param string $otherStr <p>Second string for comparison.</p>
1224
     *
1225
     * @return static <p>Object with its $str being the longest common suffix.</p>
1226
     */
1227 20
    public function longestCommonSuffix(string $otherStr): self
1228
    {
1229 20
        $longestCommonSuffix = UTF8::str_longest_common_suffix(
1230 20
            $this->str,
1231 20
            $otherStr,
1232 20
            $this->encoding
1233
        );
1234
1235 20
        return static::create($longestCommonSuffix, $this->encoding);
1236
    }
1237
1238
    /**
1239
     * Converts the first character of the string to lower case.
1240
     *
1241
     * @return static <p>Object with the first character of $str being lower case.</p>
1242
     */
1243 10
    public function lowerCaseFirst(): self
1244
    {
1245 10
        $str = UTF8::lcfirst($this->str, $this->encoding);
1246
1247 10
        return static::create($str, $this->encoding);
1248
    }
1249
1250
    /**
1251
     * Returns whether or not a character exists at an index. Offsets may be
1252
     * negative to count from the last character in the string. Implements
1253
     * part of the ArrayAccess interface.
1254
     *
1255
     * @param int $offset <p>The index to check.</p>
1256
     *
1257
     * @return bool <p>Whether or not the index exists.</p>
1258
     */
1259 12
    public function offsetExists($offset): bool
1260
    {
1261 12
        return UTF8::str_offset_exists(
1262 12
            $this->str,
1263 12
            $offset,
1264 12
            $this->encoding
1265
        );
1266
    }
1267
1268
    /**
1269
     * Returns the character at the given index. Offsets may be negative to
1270
     * count from the last character in the string. Implements part of the
1271
     * ArrayAccess interface, and throws an OutOfBoundsException if the index
1272
     * does not exist.
1273
     *
1274
     * @param int $offset <p>The <strong>index</strong> from which to retrieve the char.</p>
1275
     *
1276
     * @throws \OutOfBoundsException <p>If the positive or negative offset does not exist.</p>
1277
     *
1278
     * @return string <p>The character at the specified index.</p>
1279
     */
1280 4
    public function offsetGet($offset): string
1281
    {
1282 4
        return UTF8::str_offset_get($this->str, $offset, $this->encoding);
1283
    }
1284
1285
    /**
1286
     * Implements part of the ArrayAccess interface, but throws an exception
1287
     * when called. This maintains the immutability of Stringy objects.
1288
     *
1289
     * @param int   $offset <p>The index of the character.</p>
1290
     * @param mixed $value  <p>Value to set.</p>
1291
     *
1292
     * @throws \Exception <p>When called.</p>
1293
     */
1294 2
    public function offsetSet($offset, $value)
1295
    {
1296
        // Stringy is immutable, cannot directly set char
1297
        /** @noinspection ThrowRawExceptionInspection */
1298 2
        throw new \Exception('Stringy object is immutable, cannot modify char');
1299
    }
1300
1301
    /**
1302
     * Implements part of the ArrayAccess interface, but throws an exception
1303
     * when called. This maintains the immutability of Stringy objects.
1304
     *
1305
     * @param int $offset <p>The index of the character.</p>
1306
     *
1307
     * @throws \Exception <p>When called.</p>
1308
     */
1309 2
    public function offsetUnset($offset)
1310
    {
1311
        // Don't allow directly modifying the string
1312
        /** @noinspection ThrowRawExceptionInspection */
1313 2
        throw new \Exception('Stringy object is immutable, cannot unset char');
1314
    }
1315
1316
    /**
1317
     * Pads the string to a given length with $padStr. If length is less than
1318
     * or equal to the length of the string, no padding takes places. The
1319
     * default string used for padding is a space, and the default type (one of
1320
     * 'left', 'right', 'both') is 'right'. Throws an InvalidArgumentException
1321
     * if $padType isn't one of those 3 values.
1322
     *
1323
     * @param int    $length  <p>Desired string length after padding.</p>
1324
     * @param string $padStr  [optional] <p>String used to pad, defaults to space. Default: ' '</p>
1325
     * @param string $padType [optional] <p>One of 'left', 'right', 'both'. Default: 'right'</p>
1326
     *
1327
     * @throws \InvalidArgumentException <p>If $padType isn't one of 'right', 'left' or 'both'.</p>
1328
     *
1329
     * @return static <p>Object with a padded $str.</p>
1330
     */
1331 26
    public function pad(int $length, string $padStr = ' ', string $padType = 'right'): self
1332
    {
1333 26
        return static::create(
1334 26
            UTF8::str_pad(
1335 26
                $this->str,
1336 26
                $length,
1337 26
                $padStr,
1338 26
                $padType,
1339 26
                $this->encoding
1340
            )
1341
        );
1342
    }
1343
1344
    /**
1345
     * Returns a new string of a given length such that both sides of the
1346
     * string are padded. Alias for pad() with a $padType of 'both'.
1347
     *
1348
     * @param int    $length <p>Desired string length after padding.</p>
1349
     * @param string $padStr [optional] <p>String used to pad, defaults to space. Default: ' '</p>
1350
     *
1351
     * @return static <p>String with padding applied.</p>
1352
     */
1353 22
    public function padBoth(int $length, string $padStr = ' '): self
1354
    {
1355 22
        return static::create(
1356 22
            UTF8::str_pad_both(
1357 22
                $this->str,
1358 22
                $length,
1359 22
                $padStr,
1360 22
                $this->encoding
1361
            )
1362
        );
1363
    }
1364
1365
    /**
1366
     * Returns a new string of a given length such that the beginning of the
1367
     * string is padded. Alias for pad() with a $padType of 'left'.
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 left padding.</p>
1373
     */
1374 14
    public function padLeft(int $length, string $padStr = ' '): self
1375
    {
1376 14
        return static::create(
1377 14
            UTF8::str_pad_left(
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 end of the string
1388
     * is padded. Alias for pad() with a $padType of 'right'.
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 right padding.</p>
1394
     */
1395 14
    public function padRight(int $length, string $padStr = ' '): self
1396
    {
1397 14
        return static::create(
1398 14
            UTF8::str_pad_right(
1399 14
                $this->str,
1400 14
                $length,
1401 14
                $padStr,
1402 14
                $this->encoding
1403
            )
1404
        );
1405
    }
1406
1407
    /**
1408
     * Returns a new string starting with $string.
1409
     *
1410
     * @param string $string <p>The string to append.</p>
1411
     *
1412
     * @return static <p>Object with appended $string.</p>
1413
     */
1414 4
    public function prepend(string $string): self
1415
    {
1416 4
        return static::create($string . $this->str, $this->encoding);
1417
    }
1418
1419
    /**
1420
     * Replaces all occurrences of $pattern in $str by $replacement.
1421
     *
1422
     * @param string $pattern     <p>The regular expression pattern.</p>
1423
     * @param string $replacement <p>The string to replace with.</p>
1424
     * @param string $options     [optional] <p>Matching conditions to be used.</p>
1425
     * @param string $delimiter   [optional] <p>Delimiter the the regex. Default: '/'</p>
1426
     *
1427
     * @return static <p>Object with the result2ing $str after the replacements.</p>
1428
     */
1429 19
    public function regexReplace(string $pattern, string $replacement, string $options = '', string $delimiter = '/'): self
1430
    {
1431 19
        $str = UTF8::regex_replace(
1432 19
            $this->str,
1433 19
            $pattern,
1434 19
            $replacement,
1435 19
            $options,
1436 19
            $delimiter
1437
        );
1438
1439 19
        return static::create($str, $this->encoding);
1440
    }
1441
1442
    /**
1443
     * Remove html via "strip_tags()" from the string.
1444
     *
1445
     * @param string $allowableTags [optional] <p>You can use the optional second parameter to specify tags which should
1446
     *                              not be stripped. Default: null
1447
     *                              </p>
1448
     *
1449
     * @return static
1450
     */
1451 6
    public function removeHtml(string $allowableTags = null): self
1452
    {
1453 6
        $str = UTF8::remove_html($this->str, $allowableTags . '');
1454
1455 6
        return static::create($str, $this->encoding);
1456
    }
1457
1458
    /**
1459
     * Remove all breaks [<br> | \r\n | \r | \n | ...] from the string.
1460
     *
1461
     * @param string $replacement [optional] <p>Default is a empty string.</p>
1462
     *
1463
     * @return static
1464
     */
1465 6
    public function removeHtmlBreak(string $replacement = ''): self
1466
    {
1467 6
        $str = UTF8::remove_html_breaks($this->str, $replacement);
1468
1469 6
        return static::create($str, $this->encoding);
1470
    }
1471
1472
    /**
1473
     * Returns a new string with the prefix $substring removed, if present.
1474
     *
1475
     * @param string $substring <p>The prefix to remove.</p>
1476
     *
1477
     * @return static <p>Object having a $str without the prefix $substring.</p>
1478
     */
1479 40
    public function removeLeft(string $substring): self
1480
    {
1481 40
        $str = UTF8::remove_left($this->str, $substring, $this->encoding);
1482
1483 40
        return static::create($str, $this->encoding);
1484
    }
1485
1486
    /**
1487
     * Returns a new string with the suffix $substring removed, if present.
1488
     *
1489
     * @param string $substring <p>The suffix to remove.</p>
1490
     *
1491
     * @return static <p>Object having a $str without the suffix $substring.</p>
1492
     */
1493 40
    public function removeRight(string $substring): self
1494
    {
1495 40
        $str = UTF8::remove_right($this->str, $substring, $this->encoding);
1496
1497 40
        return static::create($str, $this->encoding);
1498
    }
1499
1500
    /**
1501
     * Try to remove all XSS-attacks from the string.
1502
     *
1503
     * @return static
1504
     */
1505 6
    public function removeXss(): self
1506
    {
1507 6
        static $antiXss = null;
1508
1509 6
        if ($antiXss === null) {
1510 1
            $antiXss = new AntiXSS();
1511
        }
1512
1513 6
        $str = $antiXss->xss_clean($this->str);
1514
1515 6
        return static::create($str, $this->encoding);
1516
    }
1517
1518
    /**
1519
     * Returns a repeated string given a multiplier.
1520
     *
1521
     * @param int $multiplier <p>The number of times to repeat the string.</p>
1522
     *
1523
     * @return static <p>Object with a repeated str.</p>
1524
     */
1525 14
    public function repeat(int $multiplier): self
1526
    {
1527 14
        $repeated = UTF8::str_repeat($this->str, $multiplier);
1528
1529 14
        return static::create($repeated, $this->encoding);
1530
    }
1531
1532
    /**
1533
     * Replaces all occurrences of $search in $str by $replacement.
1534
     *
1535
     * @param string $search        <p>The needle to search for.</p>
1536
     * @param string $replacement   <p>The string to replace with.</p>
1537
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1538
     *
1539
     * @return static <p>Object with the resulting $str after the replacements.</p>
1540
     */
1541 45
    public function replace(string $search, string $replacement, bool $caseSensitive = true): self
1542
    {
1543 45
        if ($search === '' && $replacement === '') {
1544 10
            return static::create($this->str, $this->encoding);
1545
        }
1546
1547 35
        if ($this->str === '' && $search === '') {
1548 2
            return static::create($replacement, $this->encoding);
1549
        }
1550
1551 33 View Code Duplication
        if ($caseSensitive) {
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...
1552 28
            $return = UTF8::str_replace($search, $replacement, $this->str);
1553
        } else {
1554 5
            $return = UTF8::str_ireplace($search, $replacement, $this->str);
1555
        }
1556
1557 33
        return static::create($return, $this->encoding);
1558
    }
1559
1560
    /**
1561
     * Replaces all occurrences of $search in $str by $replacement.
1562
     *
1563
     * @param array        $search        <p>The elements to search for.</p>
1564
     * @param array|string $replacement   <p>The string to replace with.</p>
1565
     * @param bool         $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1566
     *
1567
     * @return static <p>Object with the resulting $str after the replacements.</p>
1568
     */
1569 30
    public function replaceAll(array $search, $replacement, bool $caseSensitive = true): self
1570
    {
1571 30 View Code Duplication
        if ($caseSensitive) {
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...
1572 23
            $return = UTF8::str_replace($search, $replacement, $this->str);
1573
        } else {
1574 7
            $return = UTF8::str_ireplace($search, $replacement, $this->str);
1575
        }
1576
1577 30
        return static::create($return, $this->encoding);
1578
    }
1579
1580
    /**
1581
     * Replaces first occurrences of $search from the beginning of string with $replacement.
1582
     *
1583
     * @param string $search      <p>The string to search for.</p>
1584
     * @param string $replacement <p>The replacement.</p>
1585
     *
1586
     * @return static <p>Object with the resulting $str after the replacements.</p>
1587
     */
1588 16
    public function replaceFirst(string $search, string $replacement): self
1589
    {
1590 16
        $str = UTF8::str_replace_first($search, $replacement, $this->str);
1591
1592 16
        return static::create($str, $this->encoding);
1593
    }
1594
1595
    /**
1596
     * Replaces last occurrences of $search from the ending of string with $replacement.
1597
     *
1598
     * @param string $search      <p>The string to search for.</p>
1599
     * @param string $replacement <p>The replacement.</p>
1600
     *
1601
     * @return static <p>Object with the resulting $str after the replacements.</p>
1602
     */
1603 15
    public function replaceLast(string $search, string $replacement): self
1604
    {
1605 15
        $str = UTF8::str_replace_last($search, $replacement, $this->str);
1606
1607 15
        return static::create($str, $this->encoding);
1608
    }
1609
1610
    /**
1611
     * Replaces all occurrences of $search from the beginning of string with $replacement.
1612
     *
1613
     * @param string $search      <p>The string to search for.</p>
1614
     * @param string $replacement <p>The replacement.</p>
1615
     *
1616
     * @return static <p>Object with the resulting $str after the replacements.</p>
1617
     */
1618 16
    public function replaceBeginning(string $search, string $replacement): self
1619
    {
1620 16
        $str = UTF8::str_replace_beginning($this->str, $search, $replacement);
1621
1622 16
        return static::create($str, $this->encoding);
1623
    }
1624
1625
    /**
1626
     * Replaces all occurrences of $search from the ending of string with $replacement.
1627
     *
1628
     * @param string $search      <p>The string to search for.</p>
1629
     * @param string $replacement <p>The replacement.</p>
1630
     *
1631
     * @return static <p>Object with the resulting $str after the replacements.</p>
1632
     */
1633 16
    public function replaceEnding(string $search, string $replacement): self
1634
    {
1635 16
        $str = UTF8::str_replace_ending($this->str, $search, $replacement);
1636
1637 16
        return static::create($str, $this->encoding);
1638
    }
1639
1640
    /**
1641
     * Returns a reversed string. A multibyte version of strrev().
1642
     *
1643
     * @return static <p>Object with a reversed $str.</p>
1644
     */
1645 10
    public function reverse(): self
1646
    {
1647 10
        $reversed = UTF8::strrev($this->str);
1648
1649 10
        return static::create($reversed, $this->encoding);
1650
    }
1651
1652
    /**
1653
     * Truncates the string to a given length, while ensuring that it does not
1654
     * split words. If $substring is provided, and truncating occurs, the
1655
     * string is further truncated so that the substring may be appended without
1656
     * exceeding the desired length.
1657
     *
1658
     * @param int    $length    <p>Desired length of the truncated string.</p>
1659
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
1660
     * @param bool   $ignoreDoNotSplitWordsForOneWord
1661
     *
1662
     * @return static <p>Object with the resulting $str after truncating.</p>
1663
     */
1664 45
    public function safeTruncate(int $length, string $substring = '', bool $ignoreDoNotSplitWordsForOneWord = true): self
1665
    {
1666 45
        $str = UTF8::str_truncate_safe(
1667 45
            $this->str,
1668 45
            $length,
1669 45
            $substring,
1670 45
            $this->encoding,
1671 45
            $ignoreDoNotSplitWordsForOneWord
1672
        );
1673
1674 45
        return static::create($str, $this->encoding);
1675
    }
1676
1677
    /**
1678
     * Shorten the string after $length, but also after the next word.
1679
     *
1680
     * @param int    $length
1681
     * @param string $strAddOn [optional] <p>Default: '…'</p>
1682
     *
1683
     * @return static
1684
     */
1685 4
    public function shortenAfterWord(int $length, string $strAddOn = '…'): self
1686
    {
1687 4
        $string = UTF8::str_limit_after_word($this->str, $length, $strAddOn);
1688
1689 4
        return static::create($string, $this->encoding);
1690
    }
1691
1692
    /**
1693
     * A multibyte string shuffle function. It returns a string with its
1694
     * characters in random order.
1695
     *
1696
     * @return static <p>Object with a shuffled $str.</p>
1697
     */
1698 6
    public function shuffle(): self
1699
    {
1700 6
        $shuffledStr = UTF8::str_shuffle($this->str);
1701
1702 6
        return static::create($shuffledStr, $this->encoding);
1703
    }
1704
1705
    /**
1706
     * Returns the substring beginning at $start, and up to, but not including
1707
     * the index specified by $end. If $end is omitted, the function extracts
1708
     * the remaining string. If $end is negative, it is computed from the end
1709
     * of the string.
1710
     *
1711
     * @param int $start <p>Initial index from which to begin extraction.</p>
1712
     * @param int $end   [optional] <p>Index at which to end extraction. Default: null</p>
1713
     *
1714
     * @return static <p>Object with its $str being the extracted substring.</p>
1715
     */
1716 34
    public function slice(int $start, int $end = null): self
1717
    {
1718 34
        $str = UTF8::str_slice($this->str, $start, $end, $this->encoding);
1719
1720 34
        return static::create($str, $this->encoding);
1721
    }
1722
1723
    /**
1724
     * Converts the string into an URL slug. This includes replacing non-ASCII
1725
     * characters with their closest ASCII equivalents, removing remaining
1726
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
1727
     * $replacement. The replacement defaults to a single dash, and the string
1728
     * is also converted to lowercase. The language of the source string can
1729
     * also be supplied for language-specific transliteration.
1730
     *
1731
     * @param  string $replacement The string used to replace whitespace
1732
     * @param  string $language    Language of the source string
1733
     *
1734
     * @return static Object whose $str has been converted to an URL slug
1735
     */
1736 16
    public function slugify(string $replacement = '-', string $language = 'en'): self
1737
    {
1738 16
        $stringy = $this->toAscii($language);
1739 16
        $stringy->str = \str_replace('@', $replacement, $stringy);
1740 16
        $quotedReplacement = \preg_quote($replacement, '/');
1741 16
        $pattern = "/[^a-zA-Z\d\s\-_$quotedReplacement]/u";
1742 16
        $stringy->str = \preg_replace($pattern, '', $stringy);
0 ignored issues
show
Documentation Bug introduced by
It seems like \preg_replace($pattern, '', $stringy) can also be of type array<integer,string>. However, the property $str is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1743
1744 16
        return $stringy->toLowerCase()->delimit($replacement)
1745 16
                       ->removeLeft($replacement)->removeRight($replacement);
1746
    }
1747
1748
    /**
1749
     * Converts the string into an URL slug. This includes replacing non-ASCII
1750
     * characters with their closest ASCII equivalents, removing remaining
1751
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
1752
     * $replacement. The replacement defaults to a single dash, and the string
1753
     * is also converted to lowercase.
1754
     *
1755
     * @param string $replacement [optional] <p>The string used to replace whitespace. Default: '-'</p>
1756
     * @param string $language    [optional] <p>The language for the url. Default: 'de'</p>
1757
     * @param bool   $strToLower  [optional] <p>string to lower. Default: true</p>
1758
     *
1759
     * @return static <p>Object whose $str has been converted to an URL slug.</p>
1760
     */
1761 15
    public function urlify(string $replacement = '-', string $language = 'de', bool $strToLower = true): self
1762
    {
1763 15
        $slug = URLify::slug($this->str, $language, $replacement, $strToLower);
1764
1765 15
        return static::create($slug, $this->encoding);
1766
    }
1767
1768
    /**
1769
     * Convert a string to e.g.: "snake_case"
1770
     *
1771
     * @return static <p>Object with $str in snake_case.</p>
1772
     */
1773 20
    public function snakeize(): self
1774
    {
1775 20
        $str = UTF8::str_snakeize($this->str, $this->encoding);
1776
1777 20
        return static::create($str, $this->encoding);
1778
    }
1779
1780
    /**
1781
     * Splits the string with the provided regular expression, returning an
1782
     * array of Stringy objects. An optional integer $limit will truncate the
1783
     * results.
1784
     *
1785
     * @param string $pattern <p>The regex with which to split the string.</p>
1786
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no limit</p>
1787
     *
1788
     * @return static[] <p>An array of Stringy objects.</p>
1789
     */
1790 35
    public function split(string $pattern, int $limit = null): array
1791
    {
1792 35
        if ($limit === null) {
1793 7
            $limit = -1;
1794
        }
1795
1796 35
        $array = UTF8::str_split_pattern($this->str, $pattern, $limit);
1797 35
        foreach ($array as $i => &$value) {
1798 31
            $value = static::create($value, $this->encoding);
1799
        }
1800
1801 35
        return $array;
1802
    }
1803
1804
    /**
1805
     * Returns true if the string begins with $substring, false otherwise. By
1806
     * default, the comparison is case-sensitive, but can be made insensitive
1807
     * by setting $caseSensitive to false.
1808
     *
1809
     * @param string $substring     <p>The substring to look for.</p>
1810
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1811
     *
1812
     * @return bool <p>Whether or not $str starts with $substring.</p>
1813
     */
1814 22
    public function startsWith(string $substring, bool $caseSensitive = true): bool
1815
    {
1816 22
        if ($caseSensitive) {
1817 14
            return UTF8::str_starts_with($this->str, $substring);
1818
        }
1819
1820 8
        return UTF8::str_istarts_with($this->str, $substring);
1821
    }
1822
1823
    /**
1824
     * Returns true if the string begins with any of $substrings, false otherwise.
1825
     * By default the comparison is case-sensitive, but can be made insensitive by
1826
     * setting $caseSensitive to false.
1827
     *
1828
     * @param array $substrings    <p>Substrings to look for.</p>
1829
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1830
     *
1831
     * @return bool <p>Whether or not $str starts with $substring.</p>
1832
     */
1833 23
    public function startsWithAny(array $substrings, bool $caseSensitive = true): bool
1834
    {
1835 23
        if ($caseSensitive) {
1836 15
            return UTF8::str_starts_with_any($this->str, $substrings);
1837
        }
1838
1839 8
        return UTF8::str_istarts_with_any($this->str, $substrings);
1840
    }
1841
1842
    /**
1843
     * Strip all whitespace characters. This includes tabs and newline characters,
1844
     * as well as multibyte whitespace such as the thin space and ideographic space.
1845
     *
1846
     * @return static
1847
     */
1848 24
    public function stripWhitespace(): self
1849
    {
1850 24
        $str = UTF8::strip_whitespace($this->str);
1851
1852 24
        return static::create($str, $this->encoding);
1853
    }
1854
1855
    /**
1856
     * Remove css media-queries.
1857
     *
1858
     * @return static
1859
     */
1860 1
    public function stripeCssMediaQueries(): self
1861
    {
1862 1
        $str = UTF8::css_stripe_media_queries($this->str);
1863
1864 1
        return static::create($str, $this->encoding);
1865
    }
1866
1867
    /**
1868
     * Remove empty html-tag.
1869
     *
1870
     * e.g.: <tag></tag>
1871
     *
1872
     * @return static
1873
     */
1874 1
    public function stripeEmptyHtmlTags(): self
1875
    {
1876 1
        $str = UTF8::html_stripe_empty_tags($this->str);
1877
1878 1
        return static::create($str, $this->encoding);
1879
    }
1880
1881
    /**
1882
     * Returns the substring beginning at $start with the specified $length.
1883
     * It differs from the UTF8::substr() function in that providing a $length of
1884
     * null will return the rest of the string, rather than an empty string.
1885
     *
1886
     * @param int $start  <p>Position of the first character to use.</p>
1887
     * @param int $length [optional] <p>Maximum number of characters used. Default: null</p>
1888
     *
1889
     * @return static <p>Object with its $str being the substring.</p>
1890
     */
1891 18
    public function substr(int $start, int $length = null): self
1892
    {
1893 18
        $str = UTF8::substr(
1894 18
            $this->str,
1895 18
            $start,
1896 18
            $length,
1897 18
            $this->encoding
1898
        );
1899
1900 18
        return static::create($str, $this->encoding);
1901
    }
1902
1903
    /**
1904
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
1905
     * If no match is found returns new empty Stringy object.
1906
     *
1907
     * @param string $needle       <p>The string to look for.</p>
1908
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
1909
     *
1910
     * @return static
1911
     */
1912 2
    public function substringOf(string $needle, bool $beforeNeedle = false): self
1913
    {
1914 2
        $str = UTF8::str_substr_first($this->str, $needle, $beforeNeedle, $this->encoding);
1915
1916 2
        return static::create($str, $this->encoding);
1917
    }
1918
1919
    /**
1920
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
1921
     * If no match is found returns new empty Stringy object.
1922
     *
1923
     * @param string $needle       <p>The string to look for.</p>
1924
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
1925
     *
1926
     * @return static
1927
     */
1928 2
    public function substringOfIgnoreCase(string $needle, bool $beforeNeedle = false): self
1929
    {
1930 2
        $str = UTF8::str_isubstr_first($this->str, $needle, $beforeNeedle, $this->encoding);
1931
1932 2
        return static::create($str, $this->encoding);
1933
    }
1934
1935
    /**
1936
     * Surrounds $str with the given substring.
1937
     *
1938
     * @param string $substring <p>The substring to add to both sides.</P>
1939
     *
1940
     * @return static <p>Object whose $str had the substring both prepended and appended.</p>
1941
     */
1942 10
    public function surround(string $substring): self
1943
    {
1944 10
        $str = UTF8::str_surround($this->str, $substring);
1945
1946 10
        return static::create($str, $this->encoding);
1947
    }
1948
1949
    /**
1950
     * Returns a case swapped version of the string.
1951
     *
1952
     * @return static <p>Object whose $str has each character's case swapped.</P>
1953
     */
1954 10
    public function swapCase(): self
1955
    {
1956 10
        $str = UTF8::swapCase($this->str, $this->encoding);
1957
1958 10
        return static::create($str, $this->encoding);
1959
    }
1960
1961
    /**
1962
     * Returns a string with smart quotes, ellipsis characters, and dashes from
1963
     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
1964
     * equivalents.
1965
     *
1966
     * @return static <p>Object whose $str has those characters removed.</p>
1967
     */
1968 8
    public function tidy(): self
1969
    {
1970 8
        $str = UTF8::normalize_msword($this->str);
1971
1972 8
        return static::create($str, $this->encoding);
1973
    }
1974
1975
    /**
1976
     * Returns a trimmed string with the first letter of each word capitalized.
1977
     * Also accepts an array, $ignore, allowing you to list words not to be
1978
     * capitalized.
1979
     *
1980
     * @param array|null $ignore [optional] <p>An array of words not to capitalize or null. Default: null</p>
1981
     *
1982
     * @return static <p>Object with a titleized $str.</p>
1983
     */
1984 10
    public function titleize(array $ignore = null): self
1985
    {
1986 10
        $str = UTF8::str_titleize($this->str, $ignore, $this->encoding);
1987
1988 10
        return static::create($str, $this->encoding);
1989
    }
1990
1991
    /**
1992
     * Returns a trimmed string in proper title case.
1993
     *
1994
     * Also accepts an array, $ignore, allowing you to list words not to be
1995
     * capitalized.
1996
     *
1997
     * Adapted from John Gruber's script.
1998
     *
1999
     * @see https://gist.github.com/gruber/9f9e8650d68b13ce4d78
2000
     *
2001
     * @param array $ignore <p>An array of words not to capitalize.</p>
2002
     *
2003
     * @return static <p>Object with a titleized $str</p>
2004
     */
2005 35
    public function titleizeForHumans(array $ignore = []): self
2006
    {
2007 35
        $str = UTF8::str_titleize_for_humans($this->str, $ignore, $this->encoding);
2008
2009 35
        return static::create($str, $this->encoding);
2010
    }
2011
2012
    /**
2013
     * Returns an ASCII version of the string. A set of non-ASCII characters are
2014
     * replaced with their closest ASCII counterparts, and the rest are removed
2015
     * unless instructed otherwise.
2016
     *
2017
     * @param bool $strict [optional] <p>Use "transliterator_transliterate()" from PHP-Intl | WARNING: bad performance |
2018
     *                     Default: false</p>
2019
     *
2020
     * @return static <p>Object whose $str contains only ASCII characters.</p>
2021
     */
2022 16
    public function toTransliterate(bool $strict = false): self
2023
    {
2024 16
        $str = UTF8::to_ascii($this->str, '?', $strict);
2025
2026 16
        return static::create($str, $this->encoding);
2027
    }
2028
2029
    /**
2030
     * Returns an ASCII version of the string. A set of non-ASCII characters are
2031
     * replaced with their closest ASCII counterparts, and the rest are removed
2032
     * by default. The language or locale of the source string can be supplied
2033
     * for language-specific transliteration in any of the following formats:
2034
     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
2035
     * to "aeoeue" rather than "aou" as in other languages.
2036
     *
2037
     * @param string $language          Language of the source string
2038
     * @param bool   $removeUnsupported Whether or not to remove the
2039
     *                                  unsupported characters
2040
     *
2041
     * @return static Object whose $str contains only ASCII characters
2042
     */
2043 37
    public function toAscii(string $language = 'en', bool $removeUnsupported = true)
2044
    {
2045
        // init
2046 37
        $str = $this->str;
2047
2048 37
        $langSpecific = self::langSpecificCharsArray($language);
2049 37
        if (!empty($langSpecific)) {
2050 2
            $str = \str_replace($langSpecific[0], $langSpecific[1], $str);
2051
        }
2052
2053 37
        foreach ($this->charsArray() as $key => $value) {
2054 37
            $str = \str_replace($value, $key, $str);
2055
        }
2056
2057 37
        if ($removeUnsupported) {
2058 36
            $str = \preg_replace('/[^\x20-\x7E]/u', '', $str);
2059
        }
2060
2061 37
        return static::create($str, $this->encoding);
2062
    }
2063
2064
    /**
2065
     * Returns a boolean representation of the given logical string value.
2066
     * For example, 'true', '1', 'on' and 'yes' will return true. 'false', '0',
2067
     * 'off', and 'no' will return false. In all instances, case is ignored.
2068
     * For other numeric strings, their sign will determine the return value.
2069
     * In addition, blank strings consisting of only whitespace will return
2070
     * false. For all other strings, the return value is a result of a
2071
     * boolean cast.
2072
     *
2073
     * @return bool <p>A boolean value for the string.</p>
2074
     */
2075 30
    public function toBoolean(): bool
2076
    {
2077 30
        return UTF8::to_boolean($this->str);
2078
    }
2079
2080
    /**
2081
     * Converts all characters in the string to lowercase.
2082
     *
2083
     * @return static <p>Object with all characters of $str being lowercase.</p>
2084
     */
2085 28
    public function toLowerCase(): self
2086
    {
2087 28
        $str = UTF8::strtolower($this->str, $this->encoding);
2088
2089 28
        return static::create($str, $this->encoding);
2090
    }
2091
2092
    /**
2093
     * Converts each tab in the string to some number of spaces, as defined by
2094
     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
2095
     *
2096
     * @param int $tabLength [optional] <p>Number of spaces to replace each tab with. Default: 4</p>
2097
     *
2098
     * @return static <p>Object whose $str has had tabs switched to spaces.</p>
2099
     */
2100 12
    public function toSpaces(int $tabLength = 4): self
2101
    {
2102 12
        $str = UTF8::tabs_to_spaces($this->str, $tabLength);
2103
2104 12
        return static::create($str, $this->encoding);
2105
    }
2106
2107
    /**
2108
     * Return Stringy object as string, but you can also use (string) for automatically casting the object into a
2109
     * string.
2110
     *
2111
     * @return string
2112
     */
2113 1071
    public function toString(): string
2114
    {
2115 1071
        return (string) $this->str;
2116
    }
2117
2118
    /**
2119
     * Converts each occurrence of some consecutive number of spaces, as
2120
     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
2121
     * are converted to a tab.
2122
     *
2123
     * @param int $tabLength [optional] <p>Number of spaces to replace with a tab. Default: 4</p>
2124
     *
2125
     * @return static <p>Object whose $str has had spaces switched to tabs.</p>
2126
     */
2127 10
    public function toTabs(int $tabLength = 4): self
2128
    {
2129 10
        $str = UTF8::spaces_to_tabs($this->str, $tabLength);
2130
2131 10
        return static::create($str, $this->encoding);
2132
    }
2133
2134
    /**
2135
     * Converts the first character of each word in the string to uppercase
2136
     * and all other chars to lowercase.
2137
     *
2138
     * @return static <p>Object with all characters of $str being title-cased.</p>
2139
     */
2140 10
    public function toTitleCase(): self
2141
    {
2142 10
        $str = UTF8::titlecase($this->str, $this->encoding);
2143
2144 10
        return static::create($str, $this->encoding);
2145
    }
2146
2147
    /**
2148
     * Converts all characters in the string to uppercase.
2149
     *
2150
     * @return static <p>Object with all characters of $str being uppercase.</p>
2151
     */
2152 10
    public function toUpperCase(): self
2153
    {
2154 10
        $str = UTF8::strtoupper($this->str, $this->encoding);
2155
2156 10
        return static::create($str, $this->encoding);
2157
    }
2158
2159
    /**
2160
     * Returns a string with whitespace removed from the start and end of the
2161
     * string. Supports the removal of unicode whitespace. Accepts an optional
2162
     * string of characters to strip instead of the defaults.
2163
     *
2164
     * @param string $chars [optional] <p>String of characters to strip. Default: null</p>
2165
     *
2166
     * @return static <p>Object with a trimmed $str.</p>
2167
     */
2168 24
    public function trim(string $chars = null): self
2169
    {
2170 24
        $str = UTF8::trim($this->str, $chars);
2171
2172 24
        return static::create($str, $this->encoding);
2173
    }
2174
2175
    /**
2176
     * Returns a string with whitespace removed from the start of the string.
2177
     * Supports the removal of unicode whitespace. Accepts an optional
2178
     * string of characters to strip instead of the defaults.
2179
     *
2180
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
2181
     *
2182
     * @return static <p>Object with a trimmed $str.</p>
2183
     */
2184 26
    public function trimLeft(string $chars = null): self
2185
    {
2186 26
        $str = UTF8::ltrim($this->str, $chars);
2187
2188 26
        return static::create($str, $this->encoding);
2189
    }
2190
2191
    /**
2192
     * Returns a string with whitespace removed from the end of the string.
2193
     * Supports the removal of unicode whitespace. Accepts an optional
2194
     * string of characters to strip instead of the defaults.
2195
     *
2196
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
2197
     *
2198
     * @return static <p>Object with a trimmed $str.</p>
2199
     */
2200 26
    public function trimRight(string $chars = null): self
2201
    {
2202 26
        $str = UTF8::rtrim($this->str, $chars);
2203
2204 26
        return static::create($str, $this->encoding);
2205
    }
2206
2207
    /**
2208
     * Truncates the string to a given length. If $substring is provided, and
2209
     * truncating occurs, the string is further truncated so that the substring
2210
     * may be appended without exceeding the desired length.
2211
     *
2212
     * @param int    $length    <p>Desired length of the truncated string.</p>
2213
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
2214
     *
2215
     * @return static <p>Object with the resulting $str after truncating.</p>
2216
     */
2217 44
    public function truncate(int $length, string $substring = ''): self
2218
    {
2219 44
        $str = UTF8::str_truncate($this->str, $length, $substring, $this->encoding);
2220
2221 44
        return static::create($str, $this->encoding);
2222
    }
2223
2224
    /**
2225
     * Returns a lowercase and trimmed string separated by underscores.
2226
     * Underscores are inserted before uppercase characters (with the exception
2227
     * of the first character of the string), and in place of spaces as well as
2228
     * dashes.
2229
     *
2230
     * @return static <p>Object with an underscored $str.</p>
2231
     */
2232 32
    public function underscored(): self
2233
    {
2234 32
        return $this->delimit('_');
2235
    }
2236
2237
    /**
2238
     * Returns an UpperCamelCase version of the supplied string. It trims
2239
     * surrounding spaces, capitalizes letters following digits, spaces, dashes
2240
     * and underscores, and removes spaces, dashes, underscores.
2241
     *
2242
     * @return static <p>Object with $str in UpperCamelCase.</p>
2243
     */
2244 26
    public function upperCamelize(): self
2245
    {
2246 26
        $str = UTF8::str_upper_camelize($this->str, $this->encoding);
2247
2248 26
        return static::create($str, $this->encoding);
2249
    }
2250
2251
    /**
2252
     * Converts the first character of the supplied string to upper case.
2253
     *
2254
     * @return static <p>Object with the first character of $str being upper case.</p>
2255
     */
2256 12
    public function upperCaseFirst(): self
2257
    {
2258 12
        $str = UTF8::ucfirst($this->str, $this->encoding);
2259
2260 12
        return static::create($str, $this->encoding);
2261
    }
2262
2263
    /**
2264
     * Converts the string into an valid UTF-8 string.
2265
     *
2266
     * @return static
2267
     */
2268 1
    public function utf8ify(): self
2269
    {
2270 1
        $str = UTF8::cleanup($this->str);
2271
2272 1
        return static::create($str, $this->encoding);
2273
    }
2274
2275
    /**
2276
     * Returns the replacements for the toAscii() method.
2277
     *
2278
     * @return array an array of replacements
2279
     */
2280 37
    protected function charsArray(): array
2281
    {
2282 37
        static $charsArray;
2283
2284 37
        if (isset($charsArray)) {
2285 36
            return $charsArray;
2286
        }
2287
2288
        return $charsArray = [
2289 1
            '0' => ['°', '₀', '۰', '0'],
2290
            '1' => ['¹', '₁', '۱', '1'],
2291
            '2' => ['²', '₂', '۲', '2'],
2292
            '3' => ['³', '₃', '۳', '3'],
2293
            '4' => ['⁴', '₄', '۴', '٤', '4'],
2294
            '5' => ['⁵', '₅', '۵', '٥', '5'],
2295
            '6' => ['⁶', '₆', '۶', '٦', '6'],
2296
            '7' => ['⁷', '₇', '۷', '7'],
2297
            '8' => ['⁸', '₈', '۸', '8'],
2298
            '9' => ['⁹', '₉', '۹', '9'],
2299
            'a' => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ',
2300
                'ặ', 'â', 'ấ', 'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å',
2301
                'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', 'ἄ', 'ἅ', 'ἆ', 'ἇ',
2302
                'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ', 'ά',
2303
                'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ', 'အ',
2304
                'ာ', 'ါ', 'ǻ', 'ǎ', 'ª', 'ა', 'अ', 'ا', 'a', 'ä', ],
2305
            'b' => ['б', 'β', 'ب', 'ဗ', 'ბ', 'b'],
2306
            'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ', 'c'],
2307
            'd' => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ',
2308
                'д', 'δ', 'د', 'ض', 'ဍ', 'ဒ', 'დ', 'd', ],
2309
            'e' => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ',
2310
                'ệ', 'ë', 'ē', 'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ',
2311
                'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', 'έ', 'е', 'ё', 'э',
2312
                'є', 'ə', 'ဧ', 'ေ', 'ဲ', 'ე', 'ए', 'إ', 'ئ', 'e', ],
2313
            'f' => ['ф', 'φ', 'ف', 'ƒ', 'ფ', 'f'],
2314
            'g' => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ဂ', 'გ', 'گ',
2315
                'g', ],
2316
            'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ', 'h'],
2317
            'i' => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į',
2318
                'ı', 'ι', 'ί', 'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ',
2319
                'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', 'ῑ', 'ῒ', 'ΐ', 'ῖ',
2320
                'ῗ', 'і', 'ї', 'и', 'ဣ', 'ိ', 'ီ', 'ည်', 'ǐ', 'ი',
2321
                'इ', 'ی', 'i', ],
2322
            'j' => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج', 'j'],
2323
            'k' => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك', 'က', 'კ', 'ქ',
2324
                'ک', 'k', ],
2325
            'l' => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ',
2326
                'l', ],
2327
            'm' => ['м', 'μ', 'م', 'မ', 'მ', 'm'],
2328
            'n' => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن', 'န',
2329
                'ნ', 'n', ],
2330
            'o' => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ',
2331
                'ộ', 'ơ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő',
2332
                'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', 'ὄ', 'ὅ', 'ὸ', 'ό',
2333
                'о', 'و', 'θ', 'ို', 'ǒ', 'ǿ', 'º', 'ო', 'ओ', 'o',
2334
                'ö', ],
2335
            'p' => ['п', 'π', 'ပ', 'პ', 'پ', 'p'],
2336
            'q' => ['ყ', 'q'],
2337
            'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ', 'r'],
2338
            's' => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص', 'စ',
2339
                'ſ', 'ს', 's', ],
2340
            't' => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط', 'ဋ', 'တ', 'ŧ',
2341
                'თ', 'ტ', 't', ],
2342
            'u' => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ',
2343
                'ự', 'û', 'ū', 'ů', 'ű', 'ŭ', 'ų', 'µ', 'у', 'ဉ',
2344
                'ု', 'ူ', 'ǔ', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'უ', 'उ', 'u',
2345
                'ў', 'ü', ],
2346
            'v' => ['в', 'ვ', 'ϐ', 'v'],
2347
            'w' => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ', 'w'],
2348
            'x' => ['χ', 'ξ', 'x'],
2349
            'y' => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ',
2350
                'ϋ', 'ύ', 'ΰ', 'ي', 'ယ', 'y', ],
2351
            'z'    => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ', 'z'],
2352
            'aa'   => ['ع', 'आ', 'آ'],
2353
            'ae'   => ['æ', 'ǽ'],
2354
            'ai'   => ['ऐ'],
2355
            'ch'   => ['ч', 'ჩ', 'ჭ', 'چ'],
2356
            'dj'   => ['ђ', 'đ'],
2357
            'dz'   => ['џ', 'ძ'],
2358
            'ei'   => ['ऍ'],
2359
            'gh'   => ['غ', 'ღ'],
2360
            'ii'   => ['ई'],
2361
            'ij'   => ['ij'],
2362
            'kh'   => ['х', 'خ', 'ხ'],
2363
            'lj'   => ['љ'],
2364
            'nj'   => ['њ'],
2365
            'oe'   => ['œ', 'ؤ'],
2366
            'oi'   => ['ऑ'],
2367
            'oii'  => ['ऒ'],
2368
            'ps'   => ['ψ'],
2369
            'sh'   => ['ш', 'შ', 'ش'],
2370
            'shch' => ['щ'],
2371
            'ss'   => ['ß'],
2372
            'sx'   => ['ŝ'],
2373
            'th'   => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'],
2374
            'ts'   => ['ц', 'ც', 'წ'],
2375
            'uu'   => ['ऊ'],
2376
            'ya'   => ['я'],
2377
            'yu'   => ['ю'],
2378
            'zh'   => ['ж', 'ჟ', 'ژ'],
2379
            '(c)'  => ['©'],
2380
            'A'    => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ',
2381
                'Ặ', 'Â', 'Ấ', 'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą',
2382
                'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', 'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ',
2383
                'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ', 'Ᾱ',
2384
                'Ὰ', 'Ά', 'ᾼ', 'А', 'Ǻ', 'Ǎ', 'A', 'Ä', ],
2385
            'B' => ['Б', 'Β', 'ब', 'B'],
2386
            'C' => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ', 'C'],
2387
            'D' => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ',
2388
                'D', ],
2389
            'E' => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ',
2390
                'Ệ', 'Ë', 'Ē', 'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ',
2391
                'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', 'Ὲ', 'Е', 'Ё', 'Э',
2392
                'Є', 'Ə', 'E', ],
2393
            'F' => ['Ф', 'Φ', 'F'],
2394
            'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ', 'G'],
2395
            'H' => ['Η', 'Ή', 'Ħ', 'H'],
2396
            'I' => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į',
2397
                'İ', 'Ι', 'Ί', 'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ',
2398
                'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', 'І', 'Ї', 'Ǐ', 'ϒ',
2399
                'I', ],
2400
            'J' => ['J'],
2401
            'K' => ['К', 'Κ', 'K'],
2402
            'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल', 'L'],
2403
            'M' => ['М', 'Μ', 'M'],
2404
            'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν', 'N'],
2405
            'O' => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ',
2406
                'Ộ', 'Ơ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő',
2407
                'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', 'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ',
2408
                'Ό', 'О', 'Θ', 'Ө', 'Ǒ', 'Ǿ', 'O', 'Ö', ],
2409
            'P' => ['П', 'Π', 'P'],
2410
            'Q' => ['Q'],
2411
            'R' => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ', 'R'],
2412
            'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ', 'S'],
2413
            'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ', 'T'],
2414
            'U' => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ',
2415
                'Ự', 'Û', 'Ū', 'Ů', 'Ű', 'Ŭ', 'Ų', 'У', 'Ǔ', 'Ǖ',
2416
                'Ǘ', 'Ǚ', 'Ǜ', 'U', 'Ў', 'Ü', ],
2417
            'V' => ['В', 'V'],
2418
            'W' => ['Ω', 'Ώ', 'Ŵ', 'W'],
2419
            'X' => ['Χ', 'Ξ', 'X'],
2420
            'Y' => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ',
2421
                'Ы', 'Й', 'Υ', 'Ϋ', 'Ŷ', 'Y', ],
2422
            'Z'    => ['Ź', 'Ž', 'Ż', 'З', 'Ζ', 'Z'],
2423
            'AE'   => ['Æ', 'Ǽ'],
2424
            'Ch'   => ['Ч'],
2425
            'Dj'   => ['Ђ'],
2426
            'Dz'   => ['Џ'],
2427
            'Gx'   => ['Ĝ'],
2428
            'Hx'   => ['Ĥ'],
2429
            'Ij'   => ['IJ'],
2430
            'Jx'   => ['Ĵ'],
2431
            'Kh'   => ['Х'],
2432
            'Lj'   => ['Љ'],
2433
            'Nj'   => ['Њ'],
2434
            'Oe'   => ['Œ'],
2435
            'Ps'   => ['Ψ'],
2436
            'Sh'   => ['Ш'],
2437
            'Shch' => ['Щ'],
2438
            'Ss'   => ['ẞ'],
2439
            'Th'   => ['Þ'],
2440
            'Ts'   => ['Ц'],
2441
            'Ya'   => ['Я'],
2442
            'Yu'   => ['Ю'],
2443
            'Zh'   => ['Ж'],
2444
            ' '    => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81",
2445
                "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84",
2446
                "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87",
2447
                "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A",
2448
                "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80",
2449
                "\xEF\xBE\xA0", ],
2450
        ];
2451
    }
2452
2453
    /**
2454
     * Returns true if $str matches the supplied pattern, false otherwise.
2455
     *
2456
     * @param string $pattern <p>Regex pattern to match against.</p>
2457
     *
2458
     * @return bool <p>Whether or not $str matches the pattern.</p>
2459
     */
2460 12
    protected function matchesPattern(string $pattern): bool
2461
    {
2462 12
        return UTF8::str_matches_pattern($this->str, $pattern);
2463
    }
2464
2465
    /**
2466
     * Returns language-specific replacements for the toAscii() method.
2467
     * For example, German will map 'ä' to 'ae', while other languages
2468
     * will simply return 'a'.
2469
     *
2470
     * @param string $language Language of the source string
2471
     *
2472
     * @return array an array of replacements
2473
     */
2474 37
    protected static function langSpecificCharsArray(string $language = 'en'): array
2475
    {
2476 37
        $split = \preg_split('/[-_]/', $language);
2477 37
        $language = \strtolower($split[0]);
2478 37
        static $charsArray = [];
2479
2480 37
        if (isset($charsArray[$language])) {
2481 35
            return $charsArray[$language];
2482
        }
2483
2484
        $languageSpecific = [
2485 2
            'de' => [
2486
                ['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü'],
2487
                ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'],
2488
            ],
2489
            'bg' => [
2490
                ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'],
2491
                ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'],
2492
            ],
2493
        ];
2494
2495 2
        $charsArray[$language] = $languageSpecific[$language] ?? [];
2496
2497 2
        return $charsArray[$language];
2498
    }
2499
}
2500