Completed
Pull Request — master (#18)
by
unknown
02:02
created

Stringy::titleizeForHumans()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 1
rs 10
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
class Stringy implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonSerializable
13
{
14
    /**
15
     * An instance's string.
16
     *
17
     * @var string
18
     */
19
    protected $str;
20
21
    /**
22
     * The string's encoding, which should be one of the mbstring module's
23
     * supported encodings.
24
     *
25
     * @var string
26
     */
27
    protected $encoding;
28
29
    /**
30
     * @var UTF8
31
     */
32
    private $utf8;
33
34
    /**
35
     * Initializes a Stringy object and assigns both str and encoding properties
36
     * the supplied values. $str is cast to a string prior to assignment, and if
37
     * $encoding is not specified, it defaults to mb_internal_encoding(). Throws
38
     * an InvalidArgumentException if the first argument is an array or object
39
     * without a __toString method.
40
     *
41
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
42
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
43
     *
44
     * @throws \InvalidArgumentException
45
     *                                   <p>if an array or object without a
46
     *                                   __toString method is passed as the first argument</p>
47
     */
48 2200
    public function __construct($str = '', string $encoding = null)
49
    {
50 2200
        if (\is_array($str)) {
51 2
            throw new \InvalidArgumentException(
52 2
                'Passed value cannot be an array'
53
            );
54
        }
55
56
        if (
57 2198
            \is_object($str)
58
            &&
59 2198
            !\method_exists($str, '__toString')
60
        ) {
61 2
            throw new \InvalidArgumentException(
62 2
                'Passed object must have a __toString method'
63
            );
64
        }
65
66 2196
        $this->str = (string) $str;
67
68 2196
        static $UTF8 = null;
69 2196
        if ($UTF8 === null) {
70
            $UTF8 = new UTF8();
71
        }
72 2196
        $this->utf8 = $UTF8;
73
74 2196
        if ($encoding !== 'UTF-8') {
75 1435
            $this->encoding = $this->utf8::normalize_encoding($encoding, 'UTF-8');
76
        } else {
77 1657
            $this->encoding = $encoding;
78
        }
79 2196
    }
80
81
    /**
82
     * Returns the value in $str.
83
     *
84
     * @return string
85
     *                <p>The current value of the $str property.</p>
86
     */
87 982
    public function __toString()
88
    {
89 982
        return (string) $this->str;
90
    }
91
92
    /**
93
     * Returns value which can be serialized by json_encode().
94
     *
95
     * @return string The current value of the $str property
96
     */
97 1
    public function jsonSerialize()
98
    {
99 1
        return (string) $this;
100
    }
101
102
    /**
103
     * Gets the substring after the first occurrence of a separator.
104
     * If no match is found returns new empty Stringy object.
105
     *
106
     * @param string $separator
107
     *
108
     * @return static
109
     */
110 2
    public function afterFirst(string $separator): self
111
    {
112 2
        return static::create(
113 2
            $this->utf8::str_substr_after_first_separator(
114 2
                $this->str,
115 2
                $separator,
116 2
                $this->encoding
117
            )
118
        );
119
    }
120
121
    /**
122
     * Gets the substring after the first occurrence of a separator.
123
     * If no match is found returns new empty Stringy object.
124
     *
125
     * @param string $separator
126
     *
127
     * @return static
128
     */
129 1
    public function afterFirstIgnoreCase(string $separator): self
130
    {
131 1
        return static::create(
132 1
            $this->utf8::str_isubstr_after_first_separator(
133 1
                $this->str,
134 1
                $separator,
135 1
                $this->encoding
136
            )
137
        );
138
    }
139
140
    /**
141
     * Gets the substring after the last occurrence of a separator.
142
     * If no match is found returns new empty Stringy object.
143
     *
144
     * @param string $separator
145
     *
146
     * @return static
147
     */
148 1
    public function afterLast(string $separator): self
149
    {
150 1
        return static::create(
151 1
            $this->utf8::str_substr_after_last_separator(
152 1
                $this->str,
153 1
                $separator,
154 1
                $this->encoding
155
            )
156
        );
157
    }
158
159
    /**
160
     * Gets the substring after the last occurrence of a separator.
161
     * If no match is found returns new empty Stringy object.
162
     *
163
     * @param string $separator
164
     *
165
     * @return static
166
     */
167 1
    public function afterLastIgnoreCase(string $separator): self
168
    {
169 1
        return static::create(
170 1
            $this->utf8::str_isubstr_after_last_separator(
171 1
                $this->str,
172 1
                $separator,
173 1
                $this->encoding
174
            )
175
        );
176
    }
177
178
    /**
179
     * Returns a new string with $string appended.
180
     *
181
     * @param string $string <p>The string to append.</p>
182
     *
183
     * @return static
184
     *                <p>Object with appended $string.</p>
185
     */
186 8
    public function append(string $string): self
187
    {
188 8
        return static::create($this->str . $string, $this->encoding);
189
    }
190
191
    /**
192
     * Append an password (limited to chars that are good readable).
193
     *
194
     * @param int $length <p>Length of the random string.</p>
195
     *
196
     * @return static
197
     *                <p>Object with appended password.</p>
198
     */
199 1
    public function appendPassword(int $length): self
200
    {
201 1
        return $this->appendRandomString(
202 1
            $length,
203 1
            '2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ!?_#'
204
        );
205
    }
206
207
    /**
208
     * Append an random string.
209
     *
210
     * @param int    $length        <p>Length of the random string.</p>
211
     * @param string $possibleChars [optional] <p>Characters string for the random selection.</p>
212
     *
213
     * @return static
214
     *                <p>Object with appended random string.</p>
215
     */
216 2
    public function appendRandomString(int $length, string $possibleChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'): self
217
    {
218 2
        $str = $this->utf8::get_random_string($length, $possibleChars);
219
220 2
        return $this->append($str);
221
    }
222
223
    /**
224
     * Append an unique identifier.
225
     *
226
     * @param int|string $entropyExtra [optional] <p>Extra entropy via a string or int value.</p>
227
     * @param bool       $md5          [optional] <p>Return the unique identifier as md5-hash? Default: true</p>
228
     *
229
     * @return static
230
     *                <p>Object with appended unique identifier as md5-hash.</p>
231
     */
232 1
    public function appendUniqueIdentifier($entropyExtra = '', bool $md5 = true): self
233
    {
234 1
        return $this->append(
235 1
            $this->utf8::get_unique_string($entropyExtra, $md5)
236
        );
237
    }
238
239
    /**
240
     * Returns the character at $index, with indexes starting at 0.
241
     *
242
     * @param int $index <p>Position of the character.</p>
243
     *
244
     * @return static
245
     *                <p>The character at $index.</p>
246
     */
247 16
    public function at(int $index): self
248
    {
249 16
        return static::create($this->utf8::char_at($this->str, $index), $this->encoding);
250
    }
251
252
    /**
253
     * Gets the substring before the first occurrence of a separator.
254
     * If no match is found returns new empty Stringy object.
255
     *
256
     * @param string $separator
257
     *
258
     * @return static
259
     */
260 1
    public function beforeFirst(string $separator): self
261
    {
262 1
        return static::create(
263 1
            $this->utf8::str_substr_before_first_separator(
264 1
                $this->str,
265 1
                $separator,
266 1
                $this->encoding
267
            )
268
        );
269
    }
270
271
    /**
272
     * Gets the substring before the first occurrence of a separator.
273
     * If no match is found returns new empty Stringy object.
274
     *
275
     * @param string $separator
276
     *
277
     * @return static
278
     */
279 1
    public function beforeFirstIgnoreCase(string $separator): self
280
    {
281 1
        return static::create(
282 1
            $this->utf8::str_isubstr_before_first_separator(
283 1
                $this->str,
284 1
                $separator,
285 1
                $this->encoding
286
            )
287
        );
288
    }
289
290
    /**
291
     * Gets the substring before the last occurrence of a separator.
292
     * If no match is found returns new empty Stringy object.
293
     *
294
     * @param string $separator
295
     *
296
     * @return static
297
     */
298 1
    public function beforeLast(string $separator): self
299
    {
300 1
        return static::create(
301 1
            $this->utf8::str_substr_before_last_separator(
302 1
                $this->str,
303 1
                $separator,
304 1
                $this->encoding
305
            )
306
        );
307
    }
308
309
    /**
310
     * Gets the substring before the last occurrence of a separator.
311
     * If no match is found returns new empty Stringy object.
312
     *
313
     * @param string $separator
314
     *
315
     * @return static
316
     */
317 1
    public function beforeLastIgnoreCase(string $separator): self
318
    {
319 1
        return static::create(
320 1
            $this->utf8::str_isubstr_before_last_separator(
321 1
                $this->str,
322 1
                $separator,
323 1
                $this->encoding
324
            )
325
        );
326
    }
327
328
    /**
329
     * Returns the substring between $start and $end, if found, or an empty
330
     * string. An optional offset may be supplied from which to begin the
331
     * search for the start string.
332
     *
333
     * @param string $start  <p>Delimiter marking the start of the substring.</p>
334
     * @param string $end    <p>Delimiter marking the end of the substring.</p>
335
     * @param int    $offset [optional] <p>Index from which to begin the search. Default: 0</p>
336
     *
337
     * @return static
338
     *                <p>Object whose $str is a substring between $start and $end.</p>
339
     */
340 32
    public function between(string $start, string $end, int $offset = null): self
341
    {
342
        /** @noinspection UnnecessaryCastingInspection */
343 32
        $str = $this->utf8::between(
344 32
            $this->str,
345 32
            $start,
346 32
            $end,
347 32
            (int) $offset,
348 32
            $this->encoding
349
        );
350
351 32
        return static::create($str, $this->encoding);
352
    }
353
354
    /**
355
     * Returns a camelCase version of the string. Trims surrounding spaces,
356
     * capitalizes letters following digits, spaces, dashes and underscores,
357
     * and removes spaces, dashes, as well as underscores.
358
     *
359
     * @return static
360
     *                <p>Object with $str in camelCase.</p>
361
     */
362 38
    public function camelize(): self
363
    {
364 38
        return static::create(
365 38
            $this->utf8::str_camelize($this->str, $this->encoding),
366 38
            $this->encoding
367
        );
368
    }
369
370
    /**
371
     * Returns the string with the first letter of each word capitalized,
372
     * except for when the word is a name which shouldn't be capitalized.
373
     *
374
     * @return static
375
     *                <p>Object with $str capitalized.</p>
376
     */
377 39
    public function capitalizePersonalName(): self
378
    {
379 39
        return static::create(
380 39
            $this->utf8::str_capitalize_name($this->str),
381 39
            $this->encoding
382
        );
383
    }
384
385
    /**
386
     * Returns an array consisting of the characters in the string.
387
     *
388
     * @return array
389
     *               <p>An array of string chars.</p>
390
     */
391 8
    public function chars(): array
392
    {
393 8
        return $this->utf8::str_split($this->str);
394
    }
395
396
    /**
397
     * Trims the string and replaces consecutive whitespace characters with a
398
     * single space. This includes tabs and newline characters, as well as
399
     * multibyte whitespace such as the thin space and ideographic space.
400
     *
401
     * @return static
402
     *                <p>Object with a trimmed $str and condensed whitespace.</p>
403
     */
404 26
    public function collapseWhitespace(): self
405
    {
406 26
        return static::create(
407 26
            $this->utf8::collapse_whitespace($this->str),
408 26
            $this->encoding
409
        );
410
    }
411
412
    /**
413
     * Returns true if the string contains $needle, false otherwise. By default
414
     * the comparison is case-sensitive, but can be made insensitive by setting
415
     * $caseSensitive to false.
416
     *
417
     * @param string $needle        <p>Substring to look for.</p>
418
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
419
     *
420
     * @return bool
421
     *              <p>Whether or not $str contains $needle.</p>
422
     */
423 42
    public function contains(string $needle, bool $caseSensitive = true): bool
424
    {
425 42
        return $this->utf8::str_contains(
426 42
            $this->str,
427 42
            $needle,
428 42
            $caseSensitive
429
        );
430
    }
431
432
    /**
433
     * Returns true if the string contains all $needles, false otherwise. By
434
     * default the comparison is case-sensitive, but can be made insensitive by
435
     * setting $caseSensitive to false.
436
     *
437
     * @param array $needles       <p>SubStrings to look for.</p>
438
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
439
     *
440
     * @return bool
441
     *              <p>Whether or not $str contains $needle.</p>
442
     */
443 87
    public function containsAll(array $needles, bool $caseSensitive = true): bool
444
    {
445 87
        return $this->utf8::str_contains_all(
446 87
            $this->str,
447 87
            $needles,
448 87
            $caseSensitive
449
        );
450
    }
451
452
    /**
453
     * Returns true if the string contains any $needles, false otherwise. By
454
     * default the comparison is case-sensitive, but can be made insensitive by
455
     * setting $caseSensitive to false.
456
     *
457
     * @param array $needles       <p>SubStrings to look for.</p>
458
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
459
     *
460
     * @return bool
461
     *              <p>Whether or not $str contains $needle.</p>
462
     */
463 86
    public function containsAny(array $needles, bool $caseSensitive = true): bool
464
    {
465 86
        return $this->utf8::str_contains_any(
466 86
            $this->str,
467 86
            $needles,
468 86
            $caseSensitive
469
        );
470
    }
471
472
    /**
473
     * Returns the length of the string, implementing the countable interface.
474
     *
475
     * @return int
476
     *             <p>The number of characters in the string, given the encoding.</p>
477
     */
478 2
    public function count(): int
479
    {
480 2
        return $this->length();
481
    }
482
483
    /**
484
     * Returns the number of occurrences of $substring in the given string.
485
     * By default, the comparison is case-sensitive, but can be made insensitive
486
     * by setting $caseSensitive to false.
487
     *
488
     * @param string $substring     <p>The substring to search for.</p>
489
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
490
     *
491
     * @return int
492
     */
493 30
    public function countSubstr(string $substring, bool $caseSensitive = true): int
494
    {
495 30
        return $this->utf8::substr_count_simple(
496 30
            $this->str,
497 30
            $substring,
498 30
            $caseSensitive,
499 30
            $this->encoding
500
        );
501
    }
502
503
    /**
504
     * Creates a Stringy object and assigns both str and encoding properties
505
     * the supplied values. $str is cast to a string prior to assignment, and if
506
     * $encoding is not specified, it defaults to mb_internal_encoding(). It
507
     * then returns the initialized object. Throws an InvalidArgumentException
508
     * if the first argument is an array or object without a __toString method.
509
     *
510
     * @param mixed  $str      [optional] <p>Value to modify, after being cast to string. Default: ''</p>
511
     * @param string $encoding [optional] <p>The character encoding. Fallback: 'UTF-8'</p>
512
     *
513
     * @throws \InvalidArgumentException
514
     *                                   <p>if an array or object without a
515
     *                                   __toString method is passed as the first argument</p>
516
     *
517
     * @return static
518
     *                <p>A Stringy object.</p>
519
     */
520 2180
    public static function create($str = '', string $encoding = null): self
521
    {
522 2180
        return new static($str, $encoding);
523
    }
524
525
    /**
526
     * Returns a lowercase and trimmed string separated by dashes. Dashes are
527
     * inserted before uppercase characters (with the exception of the first
528
     * character of the string), and in place of spaces as well as underscores.
529
     *
530
     * @return static
531
     *                <p>Object with a dasherized $str</p>
532
     */
533 38
    public function dasherize(): self
534
    {
535 38
        return static::create(
536 38
            $this->utf8::str_dasherize($this->str),
537 38
            $this->encoding
538
        );
539
    }
540
541
    /**
542
     * Returns a lowercase and trimmed string separated by the given delimiter.
543
     * Delimiters are inserted before uppercase characters (with the exception
544
     * of the first character of the string), and in place of spaces, dashes,
545
     * and underscores. Alpha delimiters are not converted to lowercase.
546
     *
547
     * @param string $delimiter <p>Sequence used to separate parts of the string.</p>
548
     *
549
     * @return static
550
     *                <p>Object with a delimited $str.</p>
551
     */
552 60
    public function delimit(string $delimiter): self
553
    {
554 60
        return static::create(
555 60
            $this->utf8::str_delimit($this->str, $delimiter),
556 60
            $this->encoding
557
        );
558
    }
559
560
    /**
561
     * Returns true if the string ends with $substring, false otherwise. By
562
     * default, the comparison is case-sensitive, but can be made insensitive
563
     * by setting $caseSensitive to false.
564
     *
565
     * @param string $substring     <p>The substring to look for.</p>
566
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
567
     *
568
     * @return bool
569
     *              <p>Whether or not $str ends with $substring.</p>
570
     */
571 54
    public function endsWith(string $substring, bool $caseSensitive = true): bool
572
    {
573 54
        if ($caseSensitive) {
574 30
            return $this->utf8::str_ends_with($this->str, $substring);
575
        }
576
577 24
        return $this->utf8::str_iends_with($this->str, $substring);
578
    }
579
580
    /**
581
     * Returns true if the string ends with any of $substrings, false otherwise.
582
     * By default, the comparison is case-sensitive, but can be made insensitive
583
     * by setting $caseSensitive to false.
584
     *
585
     * @param string[] $substrings    <p>Substrings to look for.</p>
586
     * @param bool     $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
587
     *
588
     * @return bool
589
     *              <p>Whether or not $str ends with $substring.</p>
590
     */
591 22
    public function endsWithAny(array $substrings, bool $caseSensitive = true): bool
592
    {
593 22
        if ($caseSensitive) {
594 14
            return $this->utf8::str_ends_with_any($this->str, $substrings);
595
        }
596
597 8
        return $this->utf8::str_iends_with_any($this->str, $substrings);
598
    }
599
600
    /**
601
     * Ensures that the string begins with $substring. If it doesn't, it's
602
     * prepended.
603
     *
604
     * @param string $substring <p>The substring to add if not present.</p>
605
     *
606
     * @return static
607
     *                <p>Object with its $str prefixed by the $substring.</p>
608
     */
609 20
    public function ensureLeft(string $substring): self
610
    {
611 20
        return static::create(
612 20
            $this->utf8::str_ensure_left($this->str, $substring),
613 20
            $this->encoding
614
        );
615
    }
616
617
    /**
618
     * Ensures that the string ends with $substring. If it doesn't, it's appended.
619
     *
620
     * @param string $substring <p>The substring to add if not present.</p>
621
     *
622
     * @return static
623
     *                <p>Object with its $str suffixed by the $substring.</p>
624
     */
625 20
    public function ensureRight(string $substring): self
626
    {
627 20
        return static::create(
628 20
            $this->utf8::str_ensure_right($this->str, $substring),
629 20
            $this->encoding
630
        );
631
    }
632
633
    /**
634
     * Create a escape html version of the string via "$this->utf8::htmlspecialchars()".
635
     *
636
     * @return static
637
     */
638 6
    public function escape(): self
639
    {
640 6
        return static::create(
641 6
            $this->utf8::htmlspecialchars(
642 6
                $this->str,
643 6
                \ENT_QUOTES | \ENT_SUBSTITUTE,
644 6
                $this->encoding
645
            ),
646 6
            $this->encoding
647
        );
648
    }
649
650
    /**
651
     * Create an extract from a sentence, so if the search-string was found, it try to centered in the output.
652
     *
653
     * @param string   $search
654
     * @param int|null $length                 [optional] <p>Default: null === text->length / 2</p>
655
     * @param string   $replacerForSkippedText [optional] <p>Default: …</p>
656
     *
657
     * @return static
658
     */
659 1
    public function extractText(string $search = '', int $length = null, string $replacerForSkippedText = '…'): self
660
    {
661 1
        return static::create(
662 1
            $this->utf8::extract_text(
663 1
                $this->str,
664 1
                $search,
665 1
                $length,
666 1
                $replacerForSkippedText,
667 1
                $this->encoding
668
            ),
669 1
            $this->encoding
670
        );
671
    }
672
673
    /**
674
     * Returns the first $n characters of the string.
675
     *
676
     * @param int $n <p>Number of characters to retrieve from the start.</p>
677
     *
678
     * @return static
679
     *                <p>Object with its $str being the first $n chars.</p>
680
     */
681 25
    public function first(int $n): self
682
    {
683 25
        return static::create(
684 25
            $this->utf8::first_char($this->str, $n, $this->encoding),
685 25
            $this->encoding
686
        );
687
    }
688
689
    /**
690
     * Returns the encoding used by the Stringy object.
691
     *
692
     * @return string
693
     *                <p>The current value of the $encoding property.</p>
694
     */
695 5
    public function getEncoding(): string
696
    {
697 5
        return $this->encoding;
698
    }
699
700
    /**
701
     * Returns a new ArrayIterator, thus implementing the IteratorAggregate
702
     * interface. The ArrayIterator's constructor is passed an array of chars
703
     * in the multibyte string. This enables the use of foreach with instances
704
     * of Stringy\Stringy.
705
     *
706
     * @return \ArrayIterator
707
     *                        <p>An iterator for the characters in the string.</p>
708
     */
709 2
    public function getIterator(): \ArrayIterator
710
    {
711 2
        return new \ArrayIterator($this->chars());
712
    }
713
714
    /**
715
     * Returns true if the string contains a lower case char, false otherwise.
716
     *
717
     * @return bool
718
     *              <p>Whether or not the string contains a lower case character.</p>
719
     */
720 24
    public function hasLowerCase(): bool
721
    {
722 24
        return $this->utf8::has_lowercase($this->str);
723
    }
724
725
    /**
726
     * Returns true if the string contains an upper case char, false otherwise.
727
     *
728
     * @return bool
729
     *              <p>Whether or not the string contains an upper case character.</p>
730
     */
731 24
    public function hasUpperCase(): bool
732
    {
733 24
        return $this->utf8::has_uppercase($this->str);
734
    }
735
736
    /**
737
     * Convert all HTML entities to their applicable characters.
738
     *
739
     * @param int $flags [optional] <p>
740
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
741
     *                   which document type to use. The default is ENT_COMPAT.
742
     *                   <table>
743
     *                   Available <i>flags</i> constants
744
     *                   <tr valign="top">
745
     *                   <td>Constant Name</td>
746
     *                   <td>Description</td>
747
     *                   </tr>
748
     *                   <tr valign="top">
749
     *                   <td><b>ENT_COMPAT</b></td>
750
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
751
     *                   </tr>
752
     *                   <tr valign="top">
753
     *                   <td><b>ENT_QUOTES</b></td>
754
     *                   <td>Will convert both double and single quotes.</td>
755
     *                   </tr>
756
     *                   <tr valign="top">
757
     *                   <td><b>ENT_NOQUOTES</b></td>
758
     *                   <td>Will leave both double and single quotes unconverted.</td>
759
     *                   </tr>
760
     *                   <tr valign="top">
761
     *                   <td><b>ENT_HTML401</b></td>
762
     *                   <td>
763
     *                   Handle code as HTML 4.01.
764
     *                   </td>
765
     *                   </tr>
766
     *                   <tr valign="top">
767
     *                   <td><b>ENT_XML1</b></td>
768
     *                   <td>
769
     *                   Handle code as XML 1.
770
     *                   </td>
771
     *                   </tr>
772
     *                   <tr valign="top">
773
     *                   <td><b>ENT_XHTML</b></td>
774
     *                   <td>
775
     *                   Handle code as XHTML.
776
     *                   </td>
777
     *                   </tr>
778
     *                   <tr valign="top">
779
     *                   <td><b>ENT_HTML5</b></td>
780
     *                   <td>
781
     *                   Handle code as HTML 5.
782
     *                   </td>
783
     *                   </tr>
784
     *                   </table>
785
     *                   </p>
786
     *
787
     * @return static
788
     *                <p>Object with the resulting $str after being html decoded.</p>
789
     */
790 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...
791
    {
792 10
        return static::create(
793 10
            $this->utf8::html_entity_decode(
794 10
                $this->str,
795 10
                $flags,
796 10
                $this->encoding
797
            ),
798 10
            $this->encoding
799
        );
800
    }
801
802
    /**
803
     * Convert all applicable characters to HTML entities.
804
     *
805
     * @param int $flags [optional] <p>
806
     *                   A bitmask of one or more of the following flags, which specify how to handle quotes and
807
     *                   which document type to use. The default is ENT_COMPAT.
808
     *                   <table>
809
     *                   Available <i>flags</i> constants
810
     *                   <tr valign="top">
811
     *                   <td>Constant Name</td>
812
     *                   <td>Description</td>
813
     *                   </tr>
814
     *                   <tr valign="top">
815
     *                   <td><b>ENT_COMPAT</b></td>
816
     *                   <td>Will convert double-quotes and leave single-quotes alone.</td>
817
     *                   </tr>
818
     *                   <tr valign="top">
819
     *                   <td><b>ENT_QUOTES</b></td>
820
     *                   <td>Will convert both double and single quotes.</td>
821
     *                   </tr>
822
     *                   <tr valign="top">
823
     *                   <td><b>ENT_NOQUOTES</b></td>
824
     *                   <td>Will leave both double and single quotes unconverted.</td>
825
     *                   </tr>
826
     *                   <tr valign="top">
827
     *                   <td><b>ENT_HTML401</b></td>
828
     *                   <td>
829
     *                   Handle code as HTML 4.01.
830
     *                   </td>
831
     *                   </tr>
832
     *                   <tr valign="top">
833
     *                   <td><b>ENT_XML1</b></td>
834
     *                   <td>
835
     *                   Handle code as XML 1.
836
     *                   </td>
837
     *                   </tr>
838
     *                   <tr valign="top">
839
     *                   <td><b>ENT_XHTML</b></td>
840
     *                   <td>
841
     *                   Handle code as XHTML.
842
     *                   </td>
843
     *                   </tr>
844
     *                   <tr valign="top">
845
     *                   <td><b>ENT_HTML5</b></td>
846
     *                   <td>
847
     *                   Handle code as HTML 5.
848
     *                   </td>
849
     *                   </tr>
850
     *                   </table>
851
     *                   </p>
852
     *
853
     * @return static
854
     *                <p>Object with the resulting $str after being html encoded.</p>
855
     */
856 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...
857
    {
858 10
        return static::create(
859 10
            $this->utf8::htmlentities(
860 10
                $this->str,
861 10
                $flags,
862 10
                $this->encoding
863
            ),
864 10
            $this->encoding
865
        );
866
    }
867
868
    /**
869
     * Capitalizes the first word of the string, replaces underscores with
870
     * spaces, and strips '_id'.
871
     *
872
     * @return static
873
     *                <p>Object with a humanized $str.</p>
874
     */
875 6
    public function humanize(): self
876
    {
877 6
        return static::create(
878 6
            $this->utf8::str_humanize($this->str),
879 6
            $this->encoding
880
        );
881
    }
882
883
    /**
884
     * Returns the index of the first occurrence of $needle in the string,
885
     * and false if not found. Accepts an optional offset from which to begin
886
     * the search.
887
     *
888
     * @param string $needle <p>Substring to look for.</p>
889
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
890
     *
891
     * @return false|int
892
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
893
     */
894 20
    public function indexOf(string $needle, int $offset = 0)
895
    {
896 20
        return $this->utf8::strpos(
897 20
            $this->str,
898 20
            $needle,
899 20
            $offset,
900 20
            $this->encoding
901
        );
902
    }
903
904
    /**
905
     * Returns the index of the first occurrence of $needle in the string,
906
     * and false if not found. Accepts an optional offset from which to begin
907
     * the search.
908
     *
909
     * @param string $needle <p>Substring to look for.</p>
910
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
911
     *
912
     * @return false|int
913
     *                   <p>The occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
914
     */
915 10
    public function indexOfIgnoreCase(string $needle, int $offset = 0)
916
    {
917 10
        return $this->utf8::stripos(
918 10
            $this->str,
919 10
            $needle,
920 10
            $offset,
921 10
            $this->encoding
922
        );
923
    }
924
925
    /**
926
     * Returns the index of the last occurrence of $needle in the string,
927
     * and false if not found. Accepts an optional offset from which to begin
928
     * the search. Offsets may be negative to count from the last character
929
     * in the string.
930
     *
931
     * @param string $needle <p>Substring to look for.</p>
932
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
933
     *
934
     * @return false|int
935
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
936
     */
937 20
    public function indexOfLast(string $needle, int $offset = 0)
938
    {
939 20
        return $this->utf8::strrpos(
940 20
            $this->str,
941 20
            $needle,
942 20
            $offset,
943 20
            $this->encoding
944
        );
945
    }
946
947
    /**
948
     * Returns the index of the last occurrence of $needle in the string,
949
     * and false if not found. Accepts an optional offset from which to begin
950
     * the search. Offsets may be negative to count from the last character
951
     * in the string.
952
     *
953
     * @param string $needle <p>Substring to look for.</p>
954
     * @param int    $offset [optional] <p>Offset from which to search. Default: 0</p>
955
     *
956
     * @return false|int
957
     *                   <p>The last occurrence's <strong>index</strong> if found, otherwise <strong>false</strong>.</p>
958
     */
959 10
    public function indexOfLastIgnoreCase(string $needle, int $offset = 0)
960
    {
961 10
        return $this->utf8::strripos(
962 10
            $this->str,
963 10
            $needle,
964 10
            $offset,
965 10
            $this->encoding
966
        );
967
    }
968
969
    /**
970
     * Inserts $substring into the string at the $index provided.
971
     *
972
     * @param string $substring <p>String to be inserted.</p>
973
     * @param int    $index     <p>The index at which to insert the substring.</p>
974
     *
975
     * @return static
976
     *                <p>Object with the resulting $str after the insertion.</p>
977
     */
978 16
    public function insert(string $substring, int $index): self
979
    {
980 16
        return static::create(
981 16
            $this->utf8::str_insert(
982 16
                $this->str,
983 16
                $substring,
984 16
                $index,
985 16
                $this->encoding
986
            ),
987 16
            $this->encoding
988
        );
989
    }
990
991
    /**
992
     * Returns true if the string contains the $pattern, otherwise false.
993
     *
994
     * WARNING: Asterisks ("*") are translated into (".*") zero-or-more regular
995
     * expression wildcards.
996
     *
997
     * @credit Originally from Laravel, thanks Taylor.
998
     *
999
     * @param string $pattern <p>The string or pattern to match against.</p>
1000
     *
1001
     * @return bool
1002
     *              <p>Whether or not we match the provided pattern.</p>
1003
     */
1004 13
    public function is(string $pattern): bool
1005
    {
1006 13
        if ($this->toString() === $pattern) {
1007 1
            return true;
1008
        }
1009
1010 12
        $quotedPattern = \preg_quote($pattern, '/');
1011 12
        $replaceWildCards = \str_replace('\*', '.*', $quotedPattern);
1012
1013 12
        return $this->matchesPattern('^' . $replaceWildCards . '\z');
1014
    }
1015
1016
    /**
1017
     * Returns true if the string contains only alphabetic chars, false otherwise.
1018
     *
1019
     * @return bool
1020
     *              <p>Whether or not $str contains only alphabetic chars.</p>
1021
     */
1022 20
    public function isAlpha(): bool
1023
    {
1024 20
        return $this->utf8::is_alpha($this->str);
1025
    }
1026
1027
    /**
1028
     * Returns true if the string contains only alphabetic and numeric chars, false otherwise.
1029
     *
1030
     * @return bool
1031
     *              <p>Whether or not $str contains only alphanumeric chars.</p>
1032
     */
1033 26
    public function isAlphanumeric(): bool
1034
    {
1035 26
        return $this->utf8::is_alphanumeric($this->str);
1036
    }
1037
1038
    /**
1039
     * Returns true if the string is base64 encoded, false otherwise.
1040
     *
1041
     * @param bool $emptyStringIsValid
1042
     *
1043
     * @return bool
1044
     *              <p>Whether or not $str is base64 encoded.</p>
1045
     */
1046 14
    public function isBase64($emptyStringIsValid = true): bool
1047
    {
1048 14
        return $this->utf8::is_base64($this->str, $emptyStringIsValid);
1049
    }
1050
1051
    /**
1052
     * Returns true if the string contains only whitespace chars, false otherwise.
1053
     *
1054
     * @return bool
1055
     *              <p>Whether or not $str contains only whitespace characters.</p>
1056
     */
1057 30
    public function isBlank(): bool
1058
    {
1059 30
        return $this->utf8::is_blank($this->str);
1060
    }
1061
1062
    /**
1063
     * Returns true if the string contains a valid E-Mail address, false otherwise.
1064
     *
1065
     * @param bool $useExampleDomainCheck   [optional] <p>Default: false</p>
1066
     * @param bool $useTypoInDomainCheck    [optional] <p>Default: false</p>
1067
     * @param bool $useTemporaryDomainCheck [optional] <p>Default: false</p>
1068
     * @param bool $useDnsCheck             [optional] <p>Default: false</p>
1069
     *
1070
     * @return bool
1071
     *              <p>Whether or not $str contains a valid E-Mail address.</p>
1072
     */
1073 1
    public function isEmail(bool $useExampleDomainCheck = false, bool $useTypoInDomainCheck = false, bool $useTemporaryDomainCheck = false, bool $useDnsCheck = false): bool
1074
    {
1075 1
        return EmailCheck::isValid($this->str, $useExampleDomainCheck, $useTypoInDomainCheck, $useTemporaryDomainCheck, $useDnsCheck);
1076
    }
1077
1078
    /**
1079
     * Determine whether the string is considered to be empty.
1080
     *
1081
     * A variable is considered empty if it does not exist or if its value equals FALSE.
1082
     * empty() does not generate a warning if the variable does not exist.
1083
     *
1084
     * @return bool
1085
     *              <p>Whether or not $str is empty().</p>
1086
     */
1087 5
    public function isEmpty(): bool
1088
    {
1089 5
        return $this->utf8::is_empty($this->str);
1090
    }
1091
1092
    /**
1093
     * Returns true if the string contains only hexadecimal chars, false otherwise.
1094
     *
1095
     * @return bool
1096
     *              <p>Whether or not $str contains only hexadecimal chars.</p>
1097
     */
1098 26
    public function isHexadecimal(): bool
1099
    {
1100 26
        return $this->utf8::is_hexadecimal($this->str);
1101
    }
1102
1103
    /**
1104
     * Returns true if the string contains HTML-Tags, false otherwise.
1105
     *
1106
     * @return bool
1107
     *              <p>Whether or not $str contains HTML-Tags.</p>
1108
     */
1109 1
    public function isHtml(): bool
1110
    {
1111 1
        return $this->utf8::is_html($this->str);
1112
    }
1113
1114
    /**
1115
     * Returns true if the string is JSON, false otherwise. Unlike json_decode
1116
     * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
1117
     * in that an empty string is not considered valid JSON.
1118
     *
1119
     * @param bool $onlyArrayOrObjectResultsAreValid
1120
     *
1121
     * @return bool
1122
     *              <p>Whether or not $str is JSON.</p>
1123
     */
1124 40
    public function isJson($onlyArrayOrObjectResultsAreValid = false): bool
1125
    {
1126 40
        return $this->utf8::is_json($this->str, $onlyArrayOrObjectResultsAreValid);
1127
    }
1128
1129
    /**
1130
     * Returns true if the string contains only lower case chars, false otherwise.
1131
     *
1132
     * @return bool
1133
     *              <p>Whether or not $str contains only lower case characters.</p>
1134
     */
1135 16
    public function isLowerCase(): bool
1136
    {
1137 16
        return $this->utf8::is_lowercase($this->str);
1138
    }
1139
1140
    /**
1141
     * Returns true if the string is serialized, false otherwise.
1142
     *
1143
     * @return bool
1144
     *              <p>Whether or not $str is serialized.</p>
1145
     */
1146 14
    public function isSerialized(): bool
1147
    {
1148 14
        return $this->utf8::is_serialized($this->str);
1149
    }
1150
1151
    /**
1152
     * Returns true if the string contains only lower case chars, false
1153
     * otherwise.
1154
     *
1155
     * @return bool
1156
     *              <p>Whether or not $str contains only lower case characters.</p>
1157
     */
1158 16
    public function isUpperCase(): bool
1159
    {
1160 16
        return $this->utf8::is_uppercase($this->str);
1161
    }
1162
1163
    /**
1164
     * Returns the last $n characters of the string.
1165
     *
1166
     * @param int $n <p>Number of characters to retrieve from the end.</p>
1167
     *
1168
     * @return static
1169
     *                <p>Object with its $str being the last $n chars.</p>
1170
     */
1171 24
    public function last(int $n): self
1172
    {
1173 24
        return static::create(
1174 24
            $this->utf8::str_last_char(
1175 24
                $this->str,
1176 24
                $n,
1177 24
                $this->encoding
1178
            ),
1179 24
            $this->encoding
1180
        );
1181
    }
1182
1183
    /**
1184
     * Gets the substring after (or before via "$beforeNeedle") the last occurrence of the "$needle".
1185
     * If no match is found returns new empty Stringy object.
1186
     *
1187
     * @param string $needle       <p>The string to look for.</p>
1188
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
1189
     *
1190
     * @return static
1191
     */
1192 2 View Code Duplication
    public function lastSubstringOf(string $needle, bool $beforeNeedle = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

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

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

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

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

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

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

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

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

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

Loading history...
2090
    {
2091 2
        return static::create(
2092 2
            $this->utf8::str_substr_first(
2093 2
                $this->str,
2094 2
                $needle,
2095 2
                $beforeNeedle,
2096 2
                $this->encoding
2097
            ),
2098 2
            $this->encoding
2099
        );
2100
    }
2101
2102
    /**
2103
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
2104
     * If no match is found returns new empty Stringy object.
2105
     *
2106
     * @param string $needle       <p>The string to look for.</p>
2107
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2108
     *
2109
     * @return static
2110
     */
2111 2 View Code Duplication
    public function substringOfIgnoreCase(string $needle, bool $beforeNeedle = false): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

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

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

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

Loading history...
2294
    {
2295 12
        return static::create(
2296 12
            $this->utf8::strtolower(
2297 12
                $this->str,
2298 12
                $this->encoding,
2299 12
                false,
2300 12
                $lang,
2301 12
                $tryToKeepStringLength
2302
            ),
2303 12
            $this->encoding
2304
        );
2305
    }
2306
2307
    /**
2308
     * Converts each tab in the string to some number of spaces, as defined by
2309
     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
2310
     *
2311
     * @param int $tabLength [optional] <p>Number of spaces to replace each tab with. Default: 4</p>
2312
     *
2313
     * @return static
2314
     *                <p>Object whose $str has had tabs switched to spaces.</p>
2315
     */
2316 12 View Code Duplication
    public function toSpaces(int $tabLength = 4): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2317
    {
2318 12
        if ($tabLength === 4) {
2319 6
            $tab = '    ';
2320 6
        } elseif ($tabLength === 2) {
2321 2
            $tab = '  ';
2322
        } else {
2323 4
            $tab = \str_repeat(' ', $tabLength);
2324
        }
2325
2326 12
        return static::create(
2327 12
            \str_replace("\t", $tab, $this->str),
2328 12
            $this->encoding
2329
        );
2330
    }
2331
2332
    /**
2333
     * Return Stringy object as string, but you can also use (string) for automatically casting the object into a
2334
     * string.
2335
     *
2336
     * @return string
2337
     */
2338 1072
    public function toString(): string
2339
    {
2340 1072
        return (string) $this->str;
2341
    }
2342
2343
    /**
2344
     * Converts each occurrence of some consecutive number of spaces, as
2345
     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
2346
     * are converted to a tab.
2347
     *
2348
     * @param int $tabLength [optional] <p>Number of spaces to replace with a tab. Default: 4</p>
2349
     *
2350
     * @return static
2351
     *                <p>Object whose $str has had spaces switched to tabs.</p>
2352
     */
2353 10 View Code Duplication
    public function toTabs(int $tabLength = 4): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2354
    {
2355 10
        if ($tabLength === 4) {
2356 6
            $tab = '    ';
2357 4
        } elseif ($tabLength === 2) {
2358 2
            $tab = '  ';
2359
        } else {
2360 2
            $tab = \str_repeat(' ', $tabLength);
2361
        }
2362
2363 10
        return static::create(
2364 10
            \str_replace($tab, "\t", $this->str),
2365 10
            $this->encoding
2366
        );
2367
    }
2368
2369
    /**
2370
     * Converts the first character of each word in the string to uppercase
2371
     * and all other chars to lowercase.
2372
     *
2373
     * @return static
2374
     *                <p>Object with all characters of $str being title-cased.</p>
2375
     */
2376 10
    public function toTitleCase(): self
2377
    {
2378 10
        return static::create(
2379 10
            $this->utf8::titlecase($this->str, $this->encoding),
2380 10
            $this->encoding
2381
        );
2382
    }
2383
2384
    /**
2385
     * Converts all characters in the string to uppercase.
2386
     *
2387
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
2388
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
2389
     *
2390
     * @return static
2391
     *                <p>Object with all characters of $str being uppercase.</p>
2392
     */
2393 11 View Code Duplication
    public function toUpperCase($tryToKeepStringLength = false, $lang = null): self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

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