Completed
Push — master ( 84b6c1...9301fb )
by Lars
15:43 queued 14:21
created

Stringy::safeTruncate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 3
dl 0
loc 13
ccs 6
cts 6
cp 1
crap 1
rs 9.8333
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 2205
    public function __construct($str = '', string $encoding = null)
49
    {
50 2205
        if (\is_array($str)) {
51 2
            throw new \InvalidArgumentException(
52 2
                'Passed value cannot be an array'
53
            );
54
        }
55
56
        if (
57 2203
            \is_object($str)
58
            &&
59 2203
            !\method_exists($str, '__toString')
60
        ) {
61 2
            throw new \InvalidArgumentException(
62 2
                'Passed object must have a __toString method'
63
            );
64
        }
65
66 2201
        $this->str = (string) $str;
67
68 2201
        static $UTF8 = null;
69 2201
        if ($UTF8 === null) {
70
            $UTF8 = new UTF8();
71
        }
72 2201
        $this->utf8 = $UTF8;
73
74 2201
        if ($encoding !== 'UTF-8') {
75 1440
            $this->encoding = $this->utf8::normalize_encoding($encoding, 'UTF-8');
76
        } else {
77 1662
            $this->encoding = $encoding;
78
        }
79 2201
    }
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
                $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
                $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
                $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
                $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
                $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
                $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
                $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
                $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
            $start,
346
            $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
            $needle,
428
            $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
            $needles,
448
            $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
            $needles,
468
            $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
            $substring,
498
            $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 2185
    public static function create($str = '', string $encoding = null): self
521
    {
522 2185
        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
                $search,
665
                $length,
666
                $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
                $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
                $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
            $needle,
899
            $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
            $needle,
920
            $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
            $needle,
942
            $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
            $needle,
964
            $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
                $substring,
984
                $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
                $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
                $needle,
1198
                $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
                $needle,
1220
                $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
                $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
                $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
                $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
            $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
                $length,
1439
                $padStr,
1440
                $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
                $length,
1462
                $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
                $length,
1484
                $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
                $length,
1506
                $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
                $pattern,
1542
                $replacement,
1543
                $options,
1544
                $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
                $length,
1804
                $substring,
1805 45
                $this->encoding,
1806
                $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    [optional] <p>The string used to replace whitespace.</p>
1869
     * @param string   $language     [optional] <p>Language of the source string.</p>
1870
     * @param string[] $replacements [optional] <p>A map of replaceable strings.</p>
1871
     *
1872
     * @return static Object whose $str has been converted to an URL slug
1873
     */
1874 17
    public function slugify(
1875
        string $separator = '-',
1876
        string $language = 'en',
1877
        array $replacements = []
1878
    ): self {
1879 17
        $stringy = self::create($this->str);
1880
1881 17
        foreach ($replacements as $from => $to) {
1882 1
            $stringy->str = \str_replace($from, $to, $stringy->str);
1883
        }
1884
1885 17
        $langSpecific = self::langSpecificCharsArray($language);
1886 17
        if (!empty($langSpecific)) {
1887
            $stringy->str = \str_replace($langSpecific[0], $langSpecific[1], $stringy->str);
1888
        }
1889
1890 17
        foreach ($this->charsArray() as $key => $value) {
1891 17
            $stringy->str = \str_replace($value, $key, $stringy->str);
1892
        }
1893 17
        $stringy->str = \str_replace('@', $separator, $stringy->str);
1894
1895 17
        $stringy->str = (string) \preg_replace(
1896 17
            '/[^a-zA-Z\\d\\s\\-_' . \preg_quote($separator, '/') . ']/u',
1897 17
            '',
1898 17
            $stringy->str
1899
        );
1900 17
        $stringy->str = (string) \preg_replace('/^[\'\\s]+|[\'\\s]+$/', '', \strtolower($stringy->str));
1901 17
        $stringy->str = (string) \preg_replace('/\\B([A-Z])/', '/-\\1/', $stringy->str);
1902 17
        $stringy->str = (string) \preg_replace('/[\\-_\\s]+/', $separator, $stringy->str);
1903
1904 17
        $l = \strlen($separator);
1905 17 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...
1906 1
            $stringy->str = (string) \substr($stringy->str, $l);
1907
        }
1908
1909 17 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...
1910 1
            $stringy->str = (string) \substr($stringy->str, 0, \strlen($stringy->str) - $l);
1911
        }
1912
1913 17
        return static::create($stringy->str, $this->encoding);
1914
    }
1915
1916
    /**
1917
     * Converts the string into an URL slug. This includes replacing non-ASCII
1918
     * characters with their closest ASCII equivalents, removing remaining
1919
     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
1920
     * $replacement. The replacement defaults to a single dash, and the string
1921
     * is also converted to lowercase.
1922
     *
1923
     * @param string $separator  [optional] <p>The string used to replace whitespace. Default: '-'</p>
1924
     * @param string $language   [optional] <p>The language for the url. Default: 'de'</p>
1925
     * @param bool   $strToLower [optional] <p>string to lower. Default: true</p>
1926
     *
1927
     * @return static
1928
     *                <p>Object whose $str has been converted to an URL slug.</p>
1929
     */
1930 15
    public function urlify(
1931
        string $separator = '-',
1932
        string $language = 'de',
1933
        bool $strToLower = true
1934
    ): self {
1935 15
        return static::create(
1936 15
            URLify::slug(
1937 15
                $this->str,
1938
                $language,
1939
                $separator,
1940
                $strToLower
1941
            ),
1942 15
            $this->encoding
1943
        );
1944
    }
1945
1946
    /**
1947
     * Convert a string to e.g.: "snake_case"
1948
     *
1949
     * @return static
1950
     *                <p>Object with $str in snake_case.</p>
1951
     */
1952 20
    public function snakeize(): self
1953
    {
1954 20
        return static::create(
1955 20
            $this->utf8::str_snakeize($this->str, $this->encoding),
1956 20
            $this->encoding
1957
        );
1958
    }
1959
1960
    /**
1961
     * Splits the string with the provided regular expression, returning an
1962
     * array of Stringy objects. An optional integer $limit will truncate the
1963
     * results.
1964
     *
1965
     * @param string $pattern <p>The regex with which to split the string.</p>
1966
     * @param int    $limit   [optional] <p>Maximum number of results to return. Default: -1 === no limit</p>
1967
     *
1968
     * @return static[]
1969
     *                  <p>An array of Stringy objects.</p>
1970
     */
1971 35
    public function split(string $pattern, int $limit = null): array
1972
    {
1973 35
        if ($limit === null) {
1974 7
            $limit = -1;
1975
        }
1976
1977 35
        $array = $this->utf8::str_split_pattern($this->str, $pattern, $limit);
1978 35
        foreach ($array as $i => &$value) {
1979 31
            $value = static::create($value, $this->encoding);
1980
        }
1981
1982 35
        return $array;
1983
    }
1984
1985
    /**
1986
     * Returns true if the string begins with $substring, false otherwise. By
1987
     * default, the comparison is case-sensitive, but can be made insensitive
1988
     * by setting $caseSensitive to false.
1989
     *
1990
     * @param string $substring     <p>The substring to look for.</p>
1991
     * @param bool   $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
1992
     *
1993
     * @return bool
1994
     *              <p>Whether or not $str starts with $substring.</p>
1995
     */
1996 55
    public function startsWith(string $substring, bool $caseSensitive = true): bool
1997
    {
1998 55
        if ($caseSensitive) {
1999 30
            return $this->utf8::str_starts_with($this->str, $substring);
2000
        }
2001
2002 25
        return $this->utf8::str_istarts_with($this->str, $substring);
2003
    }
2004
2005
    /**
2006
     * Returns true if the string begins with any of $substrings, false otherwise.
2007
     * By default the comparison is case-sensitive, but can be made insensitive by
2008
     * setting $caseSensitive to false.
2009
     *
2010
     * @param array $substrings    <p>Substrings to look for.</p>
2011
     * @param bool  $caseSensitive [optional] <p>Whether or not to enforce case-sensitivity. Default: true</p>
2012
     *
2013
     * @return bool
2014
     *              <p>Whether or not $str starts with $substring.</p>
2015
     */
2016 23
    public function startsWithAny(array $substrings, bool $caseSensitive = true): bool
2017
    {
2018 23
        if ($caseSensitive) {
2019 15
            return $this->utf8::str_starts_with_any($this->str, $substrings);
2020
        }
2021
2022 8
        return $this->utf8::str_istarts_with_any($this->str, $substrings);
2023
    }
2024
2025
    /**
2026
     * Strip all whitespace characters. This includes tabs and newline characters,
2027
     * as well as multibyte whitespace such as the thin space and ideographic space.
2028
     *
2029
     * @return static
2030
     */
2031 24
    public function stripWhitespace(): self
2032
    {
2033 24
        return static::create(
2034 24
            $this->utf8::strip_whitespace($this->str),
2035 24
            $this->encoding
2036
        );
2037
    }
2038
2039
    /**
2040
     * Remove css media-queries.
2041
     *
2042
     * @return static
2043
     */
2044 1
    public function stripeCssMediaQueries(): self
2045
    {
2046 1
        return static::create(
2047 1
            $this->utf8::css_stripe_media_queries($this->str),
2048 1
            $this->encoding
2049
        );
2050
    }
2051
2052
    /**
2053
     * Remove empty html-tag.
2054
     *
2055
     * e.g.: <tag></tag>
2056
     *
2057
     * @return static
2058
     */
2059 1
    public function stripeEmptyHtmlTags(): self
2060
    {
2061 1
        return static::create(
2062 1
            $this->utf8::html_stripe_empty_tags($this->str),
2063 1
            $this->encoding
2064
        );
2065
    }
2066
2067
    /**
2068
     * Returns the substring beginning at $start with the specified $length.
2069
     * It differs from the $this->utf8::substr() function in that providing a $length of
2070
     * null will return the rest of the string, rather than an empty string.
2071
     *
2072
     * @param int $start  <p>Position of the first character to use.</p>
2073
     * @param int $length [optional] <p>Maximum number of characters used. Default: null</p>
2074
     *
2075
     * @return static
2076
     *                <p>Object with its $str being the substring.</p>
2077
     */
2078 18
    public function substr(int $start, int $length = null): self
2079
    {
2080 18
        return static::create(
2081 18
            $this->utf8::substr(
2082 18
                $this->str,
2083
                $start,
2084
                $length,
2085 18
                $this->encoding
2086
            ),
2087 18
            $this->encoding
2088
        );
2089
    }
2090
2091
    /**
2092
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
2093
     * If no match is found returns new empty Stringy object.
2094
     *
2095
     * @param string $needle       <p>The string to look for.</p>
2096
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2097
     *
2098
     * @return static
2099
     */
2100 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...
2101
    {
2102 2
        return static::create(
2103 2
            $this->utf8::str_substr_first(
2104 2
                $this->str,
2105
                $needle,
2106
                $beforeNeedle,
2107 2
                $this->encoding
2108
            ),
2109 2
            $this->encoding
2110
        );
2111
    }
2112
2113
    /**
2114
     * Gets the substring after (or before via "$beforeNeedle") the first occurrence of the "$needle".
2115
     * If no match is found returns new empty Stringy object.
2116
     *
2117
     * @param string $needle       <p>The string to look for.</p>
2118
     * @param bool   $beforeNeedle [optional] <p>Default: false</p>
2119
     *
2120
     * @return static
2121
     */
2122 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...
2123
    {
2124 2
        return static::create(
2125 2
            $this->utf8::str_isubstr_first(
2126 2
                $this->str,
2127
                $needle,
2128
                $beforeNeedle,
2129 2
                $this->encoding
2130
            ),
2131 2
            $this->encoding
2132
        );
2133
    }
2134
2135
    /**
2136
     * Surrounds $str with the given substring.
2137
     *
2138
     * @param string $substring <p>The substring to add to both sides.</P>
2139
     *
2140
     * @return static
2141
     *                <p>Object whose $str had the substring both prepended and appended.</p>
2142
     */
2143 10
    public function surround(string $substring): self
2144
    {
2145 10
        return static::create(
2146 10
            $substring . $this->str . $substring,
2147 10
            $this->encoding
2148
        );
2149
    }
2150
2151
    /**
2152
     * Returns a case swapped version of the string.
2153
     *
2154
     * @return static
2155
     *                <p>Object whose $str has each character's case swapped.</P>
2156
     */
2157 10
    public function swapCase(): self
2158
    {
2159 10
        return static::create(
2160 10
            $this->utf8::swapCase($this->str, $this->encoding),
2161 10
            $this->encoding
2162
        );
2163
    }
2164
2165
    /**
2166
     * Returns a string with smart quotes, ellipsis characters, and dashes from
2167
     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
2168
     * equivalents.
2169
     *
2170
     * @return static
2171
     *                <p>Object whose $str has those characters removed.</p>
2172
     */
2173 8
    public function tidy(): self
2174
    {
2175 8
        return static::create(
2176 8
            $this->utf8::normalize_msword($this->str),
2177 8
            $this->encoding
2178
        );
2179
    }
2180
2181
    /**
2182
     * Returns a trimmed string with the first letter of each word capitalized.
2183
     * Also accepts an array, $ignore, allowing you to list words not to be
2184
     * capitalized.
2185
     *
2186
     * @param array|string[]|null $ignore            [optional] <p>An array of words not to capitalize or null. Default: null</p>
2187
     * @param string|null         $word_define_chars [optional] <p>An string of chars that will be used as whitespace separator === words.</p>
2188
     * @param string|null         $language          [optional] <p>Language of the source string.</p>
2189
     *
2190
     * @return static
2191
     *                <p>Object with a titleized $str.</p>
2192
     */
2193 14
    public function titleize(
2194
        array $ignore = null,
2195
        string $word_define_chars = null,
2196
        string $language = null
2197
    ): self
2198
    {
2199 14
        return static::create(
2200 14
            $this->utf8::str_titleize(
2201 14
                $this->str,
2202
                $ignore,
2203 14
                $this->encoding,
2204 14
                false,
2205
                $language,
2206 14
                false,
2207 14
                true,
2208
                $word_define_chars
2209
            ),
2210 14
            $this->encoding
2211
        );
2212
    }
2213
2214
    /**
2215
     * Returns a trimmed string in proper title case.
2216
     *
2217
     * Also accepts an array, $ignore, allowing you to list words not to be
2218
     * capitalized.
2219
     *
2220
     * Adapted from John Gruber's script.
2221
     *
2222
     * @see https://gist.github.com/gruber/9f9e8650d68b13ce4d78
2223
     *
2224
     * @param array $ignore <p>An array of words not to capitalize.</p>
2225
     *
2226
     * @return static
2227
     *                <p>Object with a titleized $str</p>
2228
     */
2229 35
    public function titleizeForHumans(array $ignore = []): self
2230
    {
2231 35
        return static::create(
2232 35
            $this->utf8::str_titleize_for_humans(
2233 35
                $this->str,
2234
                $ignore,
2235 35
                $this->encoding
2236
            ),
2237 35
            $this->encoding
2238
        );
2239
    }
2240
2241
    /**
2242
     * Returns an ASCII version of the string. A set of non-ASCII characters are
2243
     * replaced with their closest ASCII counterparts, and the rest are removed
2244
     * unless instructed otherwise.
2245
     *
2246
     * @param bool $strict [optional] <p>Use "transliterator_transliterate()" from PHP-Intl | WARNING: bad performance |
2247
     *                     Default: false</p>
2248
     *
2249
     * @return static
2250
     *                <p>Object whose $str contains only ASCII characters.</p>
2251
     */
2252 16
    public function toTransliterate(bool $strict = false): self
2253
    {
2254 16
        return static::create(
2255 16
            $this->utf8::to_ascii($this->str, '?', $strict),
2256 16
            $this->encoding
2257
        );
2258
    }
2259
2260
    /**
2261
     * Returns an ASCII version of the string. A set of non-ASCII characters are
2262
     * replaced with their closest ASCII counterparts, and the rest are removed
2263
     * by default. The language or locale of the source string can be supplied
2264
     * for language-specific transliteration in any of the following formats:
2265
     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
2266
     * to "aeoeue" rather than "aou" as in other languages.
2267
     *
2268
     * @param string $language          [optional] <p>Language of the source string.</p>
2269
     * @param bool   $removeUnsupported [optional] <p>Whether or not to remove the
2270
     *                                  unsupported characters.</p>
2271
     *
2272
     * @return static
2273
     *                <p>Object whose $str contains only ASCII characters.</p>
2274
     */
2275 21
    public function toAscii(string $language = 'en', bool $removeUnsupported = true)
2276
    {
2277
        // init
2278 21
        $str = $this->str;
2279
2280 21
        $langSpecific = self::langSpecificCharsArray($language);
2281 21
        if (!empty($langSpecific)) {
2282 2
            $str = \str_replace($langSpecific[0], $langSpecific[1], $str);
2283
        }
2284
2285 21
        foreach ($this->charsArray() as $key => $value) {
2286 21
            $str = \str_replace($value, $key, $str);
2287
        }
2288
2289 21
        if ($removeUnsupported) {
2290
            /** @noinspection NotOptimalRegularExpressionsInspection */
2291 20
            $str = \preg_replace('/[^\\x20-\\x7E]/u', '', $str);
2292
        }
2293
2294 21
        return static::create($str, $this->encoding);
2295
    }
2296
2297
    /**
2298
     * Returns a boolean representation of the given logical string value.
2299
     * For example, 'true', '1', 'on' and 'yes' will return true. 'false', '0',
2300
     * 'off', and 'no' will return false. In all instances, case is ignored.
2301
     * For other numeric strings, their sign will determine the return value.
2302
     * In addition, blank strings consisting of only whitespace will return
2303
     * false. For all other strings, the return value is a result of a
2304
     * boolean cast.
2305
     *
2306
     * @return bool
2307
     *              <p>A boolean value for the string.</p>
2308
     */
2309 30
    public function toBoolean(): bool
2310
    {
2311 30
        return $this->utf8::to_boolean($this->str);
2312
    }
2313
2314
    /**
2315
     * Converts all characters in the string to lowercase.
2316
     *
2317
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
2318
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
2319
     *
2320
     * @return static
2321
     *                <p>Object with all characters of $str being lowercase.</p>
2322
     */
2323 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...
2324
    {
2325 12
        return static::create(
2326 12
            $this->utf8::strtolower(
2327 12
                $this->str,
2328 12
                $this->encoding,
2329 12
                false,
2330
                $lang,
2331
                $tryToKeepStringLength
2332
            ),
2333 12
            $this->encoding
2334
        );
2335
    }
2336
2337
    /**
2338
     * Converts each tab in the string to some number of spaces, as defined by
2339
     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
2340
     *
2341
     * @param int $tabLength [optional] <p>Number of spaces to replace each tab with. Default: 4</p>
2342
     *
2343
     * @return static
2344
     *                <p>Object whose $str has had tabs switched to spaces.</p>
2345
     */
2346 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...
2347
    {
2348 12
        if ($tabLength === 4) {
2349 6
            $tab = '    ';
2350 6
        } elseif ($tabLength === 2) {
2351 2
            $tab = '  ';
2352
        } else {
2353 4
            $tab = \str_repeat(' ', $tabLength);
2354
        }
2355
2356 12
        return static::create(
2357 12
            \str_replace("\t", $tab, $this->str),
2358 12
            $this->encoding
2359
        );
2360
    }
2361
2362
    /**
2363
     * Return Stringy object as string, but you can also use (string) for automatically casting the object into a
2364
     * string.
2365
     *
2366
     * @return string
2367
     */
2368 1077
    public function toString(): string
2369
    {
2370 1077
        return (string) $this->str;
2371
    }
2372
2373
    /**
2374
     * Converts each occurrence of some consecutive number of spaces, as
2375
     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
2376
     * are converted to a tab.
2377
     *
2378
     * @param int $tabLength [optional] <p>Number of spaces to replace with a tab. Default: 4</p>
2379
     *
2380
     * @return static
2381
     *                <p>Object whose $str has had spaces switched to tabs.</p>
2382
     */
2383 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...
2384
    {
2385 10
        if ($tabLength === 4) {
2386 6
            $tab = '    ';
2387 4
        } elseif ($tabLength === 2) {
2388 2
            $tab = '  ';
2389
        } else {
2390 2
            $tab = \str_repeat(' ', $tabLength);
2391
        }
2392
2393 10
        return static::create(
2394 10
            \str_replace($tab, "\t", $this->str),
2395 10
            $this->encoding
2396
        );
2397
    }
2398
2399
    /**
2400
     * Converts the first character of each word in the string to uppercase
2401
     * and all other chars to lowercase.
2402
     *
2403
     * @return static
2404
     *                <p>Object with all characters of $str being title-cased.</p>
2405
     */
2406 10
    public function toTitleCase(): self
2407
    {
2408 10
        return static::create(
2409 10
            $this->utf8::titlecase($this->str, $this->encoding),
2410 10
            $this->encoding
2411
        );
2412
    }
2413
2414
    /**
2415
     * Converts all characters in the string to uppercase.
2416
     *
2417
     * @param bool        $tryToKeepStringLength [optional] <p>true === try to keep the string length: e.g. ẞ -> ß</p>
2418
     * @param string|null $lang                  [optional] <p>Set the language for special cases: az, el, lt, tr</p>
2419
     *
2420
     * @return static
2421
     *                <p>Object with all characters of $str being uppercase.</p>
2422
     */
2423 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...
2424
    {
2425 11
        return static::create(
2426 11
            $this->utf8::strtoupper($this->str, $this->encoding, false, $lang, $tryToKeepStringLength),
2427 11
            $this->encoding
2428
        );
2429
    }
2430
2431
    /**
2432
     * Returns a string with whitespace removed from the start and end of the
2433
     * string. Supports the removal of unicode whitespace. Accepts an optional
2434
     * string of characters to strip instead of the defaults.
2435
     *
2436
     * @param string $chars [optional] <p>String of characters to strip. Default: null</p>
2437
     *
2438
     * @return static
2439
     *                <p>Object with a trimmed $str.</p>
2440
     */
2441 24
    public function trim(string $chars = null): self
2442
    {
2443 24
        return static::create(
2444 24
            $this->utf8::trim($this->str, $chars),
2445 24
            $this->encoding
2446
        );
2447
    }
2448
2449
    /**
2450
     * Returns a string with whitespace removed from the start of the string.
2451
     * Supports the removal of unicode whitespace. Accepts an optional
2452
     * string of characters to strip instead of the defaults.
2453
     *
2454
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
2455
     *
2456
     * @return static
2457
     *                <p>Object with a trimmed $str.</p>
2458
     */
2459 26
    public function trimLeft(string $chars = null): self
2460
    {
2461 26
        return static::create(
2462 26
            $this->utf8::ltrim($this->str, $chars),
2463 26
            $this->encoding
2464
        );
2465
    }
2466
2467
    /**
2468
     * Returns a string with whitespace removed from the end of the string.
2469
     * Supports the removal of unicode whitespace. Accepts an optional
2470
     * string of characters to strip instead of the defaults.
2471
     *
2472
     * @param string $chars [optional] <p>Optional string of characters to strip. Default: null</p>
2473
     *
2474
     * @return static
2475
     *                <p>Object with a trimmed $str.</p>
2476
     */
2477 26
    public function trimRight(string $chars = null): self
2478
    {
2479 26
        return static::create(
2480 26
            $this->utf8::rtrim($this->str, $chars),
2481 26
            $this->encoding
2482
        );
2483
    }
2484
2485
    /**
2486
     * Truncates the string to a given length. If $substring is provided, and
2487
     * truncating occurs, the string is further truncated so that the substring
2488
     * may be appended without exceeding the desired length.
2489
     *
2490
     * @param int    $length    <p>Desired length of the truncated string.</p>
2491
     * @param string $substring [optional] <p>The substring to append if it can fit. Default: ''</p>
2492
     *
2493
     * @return static
2494
     *                <p>Object with the resulting $str after truncating.</p>
2495
     */
2496 44
    public function truncate(int $length, string $substring = ''): self
2497
    {
2498 44
        return static::create(
2499 44
            $this->utf8::str_truncate($this->str, $length, $substring, $this->encoding),
2500 44
            $this->encoding
2501
        );
2502
    }
2503
2504
    /**
2505
     * Returns a lowercase and trimmed string separated by underscores.
2506
     * Underscores are inserted before uppercase characters (with the exception
2507
     * of the first character of the string), and in place of spaces as well as
2508
     * dashes.
2509
     *
2510
     * @return static
2511
     *                <p>Object with an underscored $str.</p>
2512
     */
2513 32
    public function underscored(): self
2514
    {
2515 32
        return $this->delimit('_');
2516
    }
2517
2518
    /**
2519
     * Returns an UpperCamelCase version of the supplied string. It trims
2520
     * surrounding spaces, capitalizes letters following digits, spaces, dashes
2521
     * and underscores, and removes spaces, dashes, underscores.
2522
     *
2523
     * @return static
2524
     *                <p>Object with $str in UpperCamelCase.</p>
2525
     */
2526 26
    public function upperCamelize(): self
2527
    {
2528 26
        return static::create(
2529 26
            $this->utf8::str_upper_camelize($this->str, $this->encoding),
2530 26
            $this->encoding
2531
        );
2532
    }
2533
2534
    /**
2535
     * Converts the first character of the supplied string to upper case.
2536
     *
2537
     * @return static
2538
     *                <p>Object with the first character of $str being upper case.</p>
2539
     */
2540 12
    public function upperCaseFirst(): self
2541
    {
2542 12
        return static::create($this->utf8::ucfirst($this->str, $this->encoding), $this->encoding);
2543
    }
2544
2545
    /**
2546
     * Converts the string into an valid UTF-8 string.
2547
     *
2548
     * @return static
2549
     */
2550 1
    public function utf8ify(): self
2551
    {
2552 1
        return static::create($this->utf8::cleanup($this->str), $this->encoding);
2553
    }
2554
2555
    /**
2556
     * Returns the replacements for the toAscii() method.
2557
     *
2558
     * @return array
2559
     *               <p>An array of replacements.</p>
2560
     */
2561 38
    protected function charsArray(): array
2562
    {
2563 38
        static $charsArray;
2564
2565
        /** @noinspection NullCoalescingOperatorCanBeUsedInspection */
2566 38
        if (isset($charsArray)) {
2567 37
            return $charsArray;
2568
        }
2569
2570
        return $charsArray = [
2571 1
            '0' => ['°', '₀', '۰', '0'],
2572
            '1' => ['¹', '₁', '۱', '1'],
2573
            '2' => ['²', '₂', '۲', '2'],
2574
            '3' => ['³', '₃', '۳', '3'],
2575
            '4' => ['⁴', '₄', '۴', '٤', '4'],
2576
            '5' => ['⁵', '₅', '۵', '٥', '5'],
2577
            '6' => ['⁶', '₆', '۶', '٦', '6'],
2578
            '7' => ['⁷', '₇', '۷', '7'],
2579
            '8' => ['⁸', '₈', '۸', '8'],
2580
            '9' => ['⁹', '₉', '۹', '9'],
2581
            'a' => [
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
                'ἆ',
2611
                'ἇ',
2612
                'ᾀ',
2613
                'ᾁ',
2614
                'ᾂ',
2615
                'ᾃ',
2616
                'ᾄ',
2617
                'ᾅ',
2618
                'ᾆ',
2619
                'ᾇ',
2620
                'ὰ',
2621
                'ά',
2622
                'ᾰ',
2623
                'ᾱ',
2624
                'ᾲ',
2625
                'ᾳ',
2626
                'ᾴ',
2627
                'ᾶ',
2628
                'ᾷ',
2629
                'а',
2630
                'أ',
2631
                'အ',
2632
                'ာ',
2633
                'ါ',
2634
                'ǻ',
2635
                'ǎ',
2636
                'ª',
2637
                'ა',
2638
                'अ',
2639
                'ا',
2640
                'a',
2641
                'ä',
2642
            ],
2643
            'b' => ['б', 'β', 'ب', 'ဗ', 'ბ', 'b'],
2644
            'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ', 'c'],
2645
            'd' => [
2646
                'ď',
2647
                'ð',
2648
                'đ',
2649
                'ƌ',
2650
                'ȡ',
2651
                'ɖ',
2652
                'ɗ',
2653
                'ᵭ',
2654
                'ᶁ',
2655
                'ᶑ',
2656
                'д',
2657
                'δ',
2658
                'د',
2659
                'ض',
2660
                'ဍ',
2661
                'ဒ',
2662
                'დ',
2663
                'd',
2664
            ],
2665
            'e' => [
2666
                'é',
2667
                'è',
2668
                'ẻ',
2669
                'ẽ',
2670
                'ẹ',
2671
                'ê',
2672
                'ế',
2673
                'ề',
2674
                'ể',
2675
                'ễ',
2676
                'ệ',
2677
                'ë',
2678
                'ē',
2679
                'ę',
2680
                'ě',
2681
                'ĕ',
2682
                'ė',
2683
                'ε',
2684
                'έ',
2685
                'ἐ',
2686
                'ἑ',
2687
                'ἒ',
2688
                'ἓ',
2689
                'ἔ',
2690
                'ἕ',
2691
                'ὲ',
2692
                'έ',
2693
                'е',
2694
                'ё',
2695
                'э',
2696
                'є',
2697
                'ə',
2698
                'ဧ',
2699
                'ေ',
2700
                'ဲ',
2701
                'ე',
2702
                'ए',
2703
                'إ',
2704
                'ئ',
2705
                'e',
2706
            ],
2707
            'f' => ['ф', 'φ', 'ف', 'ƒ', 'ფ', 'f'],
2708
            'g' => [
2709
                'ĝ',
2710
                'ğ',
2711
                'ġ',
2712
                'ģ',
2713
                'г',
2714
                'ґ',
2715
                'γ',
2716
                'ဂ',
2717
                'გ',
2718
                'گ',
2719
                'g',
2720
            ],
2721
            'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ', 'h'],
2722
            'i' => [
2723
                'í',
2724
                'ì',
2725
                'ỉ',
2726
                'ĩ',
2727
                'ị',
2728
                'î',
2729
                'ï',
2730
                'ī',
2731
                'ĭ',
2732
                'į',
2733
                'ı',
2734
                'ι',
2735
                'ί',
2736
                'ϊ',
2737
                'ΐ',
2738
                'ἰ',
2739
                'ἱ',
2740
                'ἲ',
2741
                'ἳ',
2742
                'ἴ',
2743
                'ἵ',
2744
                'ἶ',
2745
                'ἷ',
2746
                'ὶ',
2747
                'ί',
2748
                'ῐ',
2749
                'ῑ',
2750
                'ῒ',
2751
                'ΐ',
2752
                'ῖ',
2753
                'ῗ',
2754
                'і',
2755
                'ї',
2756
                'и',
2757
                'ဣ',
2758
                'ိ',
2759
                'ီ',
2760
                'ည်',
2761
                'ǐ',
2762
                'ი',
2763
                'इ',
2764
                'ی',
2765
                'i',
2766
            ],
2767
            'j' => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج', 'j'],
2768
            'k' => [
2769
                'ķ',
2770
                'ĸ',
2771
                'к',
2772
                'κ',
2773
                'Ķ',
2774
                'ق',
2775
                'ك',
2776
                'က',
2777
                'კ',
2778
                'ქ',
2779
                'ک',
2780
                'k',
2781
            ],
2782
            'l' => [
2783
                'ł',
2784
                'ľ',
2785
                'ĺ',
2786
                'ļ',
2787
                'ŀ',
2788
                'л',
2789
                'λ',
2790
                'ل',
2791
                'လ',
2792
                'ლ',
2793
                'l',
2794
            ],
2795
            'm' => ['м', 'μ', 'م', 'မ', 'მ', 'm'],
2796
            'n' => [
2797
                'ñ',
2798
                'ń',
2799
                'ň',
2800
                'ņ',
2801
                'ʼn',
2802
                'ŋ',
2803
                'ν',
2804
                'н',
2805
                'ن',
2806
                'န',
2807
                'ნ',
2808
                'n',
2809
            ],
2810
            'o' => [
2811
                'ó',
2812
                'ò',
2813
                'ỏ',
2814
                'õ',
2815
                'ọ',
2816
                'ô',
2817
                'ố',
2818
                'ồ',
2819
                'ổ',
2820
                'ỗ',
2821
                'ộ',
2822
                'ơ',
2823
                'ớ',
2824
                'ờ',
2825
                'ở',
2826
                'ỡ',
2827
                'ợ',
2828
                'ø',
2829
                'ō',
2830
                'ő',
2831
                'ŏ',
2832
                'ο',
2833
                'ὀ',
2834
                'ὁ',
2835
                'ὂ',
2836
                'ὃ',
2837
                'ὄ',
2838
                'ὅ',
2839
                'ὸ',
2840
                'ό',
2841
                'о',
2842
                'و',
2843
                'ို',
2844
                'ǒ',
2845
                'ǿ',
2846
                'º',
2847
                'ო',
2848
                'ओ',
2849
                'o',
2850
                'ö',
2851
            ],
2852
            'p' => ['п', 'π', 'ပ', 'პ', 'پ', 'p'],
2853
            'q' => ['ყ', 'q'],
2854
            'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ', 'r'],
2855
            's' => [
2856
                'ś',
2857
                'š',
2858
                'ş',
2859
                'с',
2860
                'σ',
2861
                'ș',
2862
                'ς',
2863
                'س',
2864
                'ص',
2865
                'စ',
2866
                'ſ',
2867
                'ს',
2868
                's',
2869
            ],
2870
            't' => [
2871
                'ť',
2872
                'ţ',
2873
                'т',
2874
                'τ',
2875
                'ț',
2876
                'ت',
2877
                'ط',
2878
                'ဋ',
2879
                'တ',
2880
                'ŧ',
2881
                'თ',
2882
                'ტ',
2883
                't',
2884
            ],
2885
            'u' => [
2886
                'ú',
2887
                'ù',
2888
                'ủ',
2889
                'ũ',
2890
                'ụ',
2891
                'ư',
2892
                'ứ',
2893
                'ừ',
2894
                'ử',
2895
                'ữ',
2896
                'ự',
2897
                'û',
2898
                'ū',
2899
                'ů',
2900
                'ű',
2901
                'ŭ',
2902
                'ų',
2903
                'µ',
2904
                'у',
2905
                'ဉ',
2906
                'ု',
2907
                'ူ',
2908
                'ǔ',
2909
                'ǖ',
2910
                'ǘ',
2911
                'ǚ',
2912
                'ǜ',
2913
                'უ',
2914
                'उ',
2915
                'u',
2916
                'ў',
2917
                'ü',
2918
            ],
2919
            'v' => ['в', 'ვ', 'ϐ', 'v'],
2920
            'w' => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ', 'w'],
2921
            'x' => ['χ', 'ξ', 'x'],
2922
            'y' => [
2923
                'ý',
2924
                'ỳ',
2925
                'ỷ',
2926
                'ỹ',
2927
                'ỵ',
2928
                'ÿ',
2929
                'ŷ',
2930
                'й',
2931
                'ы',
2932
                'υ',
2933
                'ϋ',
2934
                'ύ',
2935
                'ΰ',
2936
                'ي',
2937
                'ယ',
2938
                'y',
2939
            ],
2940
            'z'    => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ', 'z'],
2941
            'aa'   => ['ع', 'आ', 'آ'],
2942
            'ae'   => ['æ', 'ǽ'],
2943
            'ai'   => ['ऐ'],
2944
            'ch'   => ['ч', 'ჩ', 'ჭ', 'چ'],
2945
            'dj'   => ['ђ', 'đ'],
2946
            'dz'   => ['џ', 'ძ'],
2947
            'ei'   => ['ऍ'],
2948
            'gh'   => ['غ', 'ღ'],
2949
            'ii'   => ['ई'],
2950
            'ij'   => ['ij'],
2951
            'kh'   => ['х', 'خ', 'ხ'],
2952
            'lj'   => ['љ'],
2953
            'nj'   => ['њ'],
2954
            'oe'   => ['œ', 'ؤ'],
2955
            'oi'   => ['ऑ'],
2956
            'oii'  => ['ऒ'],
2957
            'ps'   => ['ψ'],
2958
            'sh'   => ['ш', 'შ', 'ش'],
2959
            'shch' => ['щ'],
2960
            'ss'   => ['ß'],
2961
            'sx'   => ['ŝ'],
2962
            'th'   => ['þ', 'ϑ', 'θ', 'ث', 'ذ', 'ظ'],
2963
            'ts'   => ['ц', 'ც', 'წ'],
2964
            'uu'   => ['ऊ'],
2965
            'ya'   => ['я'],
2966
            'yu'   => ['ю'],
2967
            'zh'   => ['ж', 'ჟ', 'ژ'],
2968
            '(c)'  => ['©'],
2969
            'A'    => [
2970
                'Á',
2971
                'À',
2972
                'Ả',
2973
                'Ã',
2974
                'Ạ',
2975
                'Ă',
2976
                'Ắ',
2977
                'Ằ',
2978
                'Ẳ',
2979
                'Ẵ',
2980
                'Ặ',
2981
                'Â',
2982
                'Ấ',
2983
                'Ầ',
2984
                'Ẩ',
2985
                'Ẫ',
2986
                'Ậ',
2987
                'Å',
2988
                'Ā',
2989
                'Ą',
2990
                'Α',
2991
                'Ά',
2992
                'Ἀ',
2993
                'Ἁ',
2994
                'Ἂ',
2995
                'Ἃ',
2996
                'Ἄ',
2997
                'Ἅ',
2998
                'Ἆ',
2999
                'Ἇ',
3000
                'ᾈ',
3001
                'ᾉ',
3002
                'ᾊ',
3003
                'ᾋ',
3004
                'ᾌ',
3005
                'ᾍ',
3006
                'ᾎ',
3007
                'ᾏ',
3008
                'Ᾰ',
3009
                'Ᾱ',
3010
                'Ὰ',
3011
                'Ά',
3012
                'ᾼ',
3013
                'А',
3014
                'Ǻ',
3015
                'Ǎ',
3016
                'A',
3017
                'Ä',
3018
            ],
3019
            'B' => ['Б', 'Β', 'ब', 'B'],
3020
            'C' => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ', 'C'],
3021
            'D' => [
3022
                'Ď',
3023
                'Ð',
3024
                'Đ',
3025
                'Ɖ',
3026
                'Ɗ',
3027
                'Ƌ',
3028
                'ᴅ',
3029
                'ᴆ',
3030
                'Д',
3031
                'Δ',
3032
                'D',
3033
            ],
3034
            'E' => [
3035
                'É',
3036
                'È',
3037
                'Ẻ',
3038
                'Ẽ',
3039
                'Ẹ',
3040
                'Ê',
3041
                'Ế',
3042
                'Ề',
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
                'E',
3068
            ],
3069
            'F' => ['Ф', 'Φ', 'F'],
3070
            'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ', 'G'],
3071
            'H' => ['Η', 'Ή', 'Ħ', 'H'],
3072
            'I' => [
3073
                'Í',
3074
                'Ì',
3075
                'Ỉ',
3076
                'Ĩ',
3077
                'Ị',
3078
                'Î',
3079
                'Ï',
3080
                'Ī',
3081
                'Ĭ',
3082
                'Į',
3083
                'İ',
3084
                'Ι',
3085
                'Ί',
3086
                'Ϊ',
3087
                'Ἰ',
3088
                'Ἱ',
3089
                'Ἳ',
3090
                'Ἴ',
3091
                'Ἵ',
3092
                'Ἶ',
3093
                'Ἷ',
3094
                'Ῐ',
3095
                'Ῑ',
3096
                'Ὶ',
3097
                'Ί',
3098
                'И',
3099
                'І',
3100
                'Ї',
3101
                'Ǐ',
3102
                'ϒ',
3103
                'I',
3104
            ],
3105
            'J' => ['J'],
3106
            'K' => ['К', 'Κ', 'K'],
3107
            'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल', 'L'],
3108
            'M' => ['М', 'Μ', 'M'],
3109
            'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν', 'N'],
3110
            'O' => [
3111
                'Ó',
3112
                'Ò',
3113
                'Ỏ',
3114
                'Õ',
3115
                'Ọ',
3116
                'Ô',
3117
                'Ố',
3118
                'Ồ',
3119
                'Ổ',
3120
                'Ỗ',
3121
                'Ộ',
3122
                'Ơ',
3123
                'Ớ',
3124
                'Ờ',
3125
                'Ở',
3126
                'Ỡ',
3127
                'Ợ',
3128
                'Ø',
3129
                'Ō',
3130
                'Ő',
3131
                'Ŏ',
3132
                'Ο',
3133
                'Ό',
3134
                'Ὀ',
3135
                'Ὁ',
3136
                'Ὂ',
3137
                'Ὃ',
3138
                'Ὄ',
3139
                'Ὅ',
3140
                'Ὸ',
3141
                'Ό',
3142
                'О',
3143
                'Ө',
3144
                'Ǒ',
3145
                'Ǿ',
3146
                'O',
3147
                'Ö',
3148
            ],
3149
            'P' => ['П', 'Π', 'P'],
3150
            'Q' => ['Q'],
3151
            'R' => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ', 'R'],
3152
            'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ', 'S'],
3153
            'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ', 'T'],
3154
            'U' => [
3155
                'Ú',
3156
                'Ù',
3157
                'Ủ',
3158
                'Ũ',
3159
                'Ụ',
3160
                'Ư',
3161
                'Ứ',
3162
                'Ừ',
3163
                'Ử',
3164
                'Ữ',
3165
                'Ự',
3166
                'Û',
3167
                'Ū',
3168
                'Ů',
3169
                'Ű',
3170
                'Ŭ',
3171
                'Ų',
3172
                'У',
3173
                'Ǔ',
3174
                'Ǖ',
3175
                'Ǘ',
3176
                'Ǚ',
3177
                'Ǜ',
3178
                'U',
3179
                'Ў',
3180
                'Ü',
3181
            ],
3182
            'V' => ['В', 'V'],
3183
            'W' => ['Ω', 'Ώ', 'Ŵ', 'W'],
3184
            'X' => ['Χ', 'Ξ', 'X'],
3185
            'Y' => [
3186
                'Ý',
3187
                'Ỳ',
3188
                'Ỷ',
3189
                'Ỹ',
3190
                'Ỵ',
3191
                'Ÿ',
3192
                'Ῠ',
3193
                'Ῡ',
3194
                'Ὺ',
3195
                'Ύ',
3196
                'Ы',
3197
                'Й',
3198
                'Υ',
3199
                'Ϋ',
3200
                'Ŷ',
3201
                'Y',
3202
            ],
3203
            'Z'    => ['Ź', 'Ž', 'Ż', 'З', 'Ζ', 'Z'],
3204
            'AE'   => ['Æ', 'Ǽ'],
3205
            'Ch'   => ['Ч'],
3206
            'Dj'   => ['Ђ'],
3207
            'Dz'   => ['Џ'],
3208
            'Gx'   => ['Ĝ'],
3209
            'Hx'   => ['Ĥ'],
3210
            'Ij'   => ['IJ'],
3211
            'Jx'   => ['Ĵ'],
3212
            'Kh'   => ['Х'],
3213
            'Lj'   => ['Љ'],
3214
            'Nj'   => ['Њ'],
3215
            'Oe'   => ['Œ'],
3216
            'Ps'   => ['Ψ'],
3217
            'Sh'   => ['Ш'],
3218
            'Shch' => ['Щ'],
3219
            'Ss'   => ['ẞ'],
3220
            'Th'   => ['Þ', 'Θ'],
3221
            'Ts'   => ['Ц'],
3222
            'Ya'   => ['Я'],
3223
            'Yu'   => ['Ю'],
3224
            'Zh'   => ['Ж'],
3225
            ' '    => [
3226
                "\xC2\xA0",
3227
                "\xE2\x80\x80",
3228
                "\xE2\x80\x81",
3229
                "\xE2\x80\x82",
3230
                "\xE2\x80\x83",
3231
                "\xE2\x80\x84",
3232
                "\xE2\x80\x85",
3233
                "\xE2\x80\x86",
3234
                "\xE2\x80\x87",
3235
                "\xE2\x80\x88",
3236
                "\xE2\x80\x89",
3237
                "\xE2\x80\x8A",
3238
                "\xE2\x80\xAF",
3239
                "\xE2\x81\x9F",
3240
                "\xE3\x80\x80",
3241
                "\xEF\xBE\xA0",
3242
            ],
3243
        ];
3244
    }
3245
3246
    /**
3247
     * Returns true if $str matches the supplied pattern, false otherwise.
3248
     *
3249
     * @param string $pattern <p>Regex pattern to match against.</p>
3250
     *
3251
     * @return bool
3252
     *              <p>Whether or not $str matches the pattern.</p>
3253
     */
3254 12
    protected function matchesPattern(string $pattern): bool
3255
    {
3256 12
        return $this->utf8::str_matches_pattern($this->str, $pattern);
3257
    }
3258
3259
    /**
3260
     * Returns language-specific replacements for the toAscii() method.
3261
     * For example, German will map 'ä' to 'ae', while other languages
3262
     * will simply return 'a'.
3263
     *
3264
     * @param string $language [optional] <p>Language of the source string</p>
3265
     *
3266
     * @return array an array of replacements
3267
     */
3268 38
    protected static function langSpecificCharsArray(string $language = 'en'): array
3269
    {
3270 38
        $split = \preg_split('/[-_]/', $language);
3271 38
        if ($split === false) {
3272
            return [];
3273
        }
3274
3275 38
        if (!isset($split[0])) {
3276
            return [];
3277
        }
3278
3279 38
        $language = \strtolower($split[0]);
3280 38
        static $charsArray = [];
3281
3282 38
        if (isset($charsArray[$language])) {
3283 36
            return $charsArray[$language];
3284
        }
3285
3286
        $languageSpecific = [
3287
            'de' => [
3288 2
                ['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü'],
3289
                ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'],
3290
            ],
3291
            'bg' => [
3292
                ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'],
3293
                ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'],
3294
            ],
3295
        ];
3296
3297 2
        $charsArray[$language] = $languageSpecific[$language] ?? [];
3298
3299 2
        return $charsArray[$language];
3300
    }
3301
}
3302