Passed
Branch dev (98b723)
by Sergey
02:12
created

Strings::lastSegment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 1
b 0
f 1
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Flextype\Component\Strings;
6
7
use function abs;
8
use function array_reverse;
9
use function array_shift;
10
use function ctype_lower;
11
use function explode;
12
use function implode;
13
use function lcfirst;
14
use function ltrim;
15
use function mb_convert_case;
16
use function mb_strimwidth;
17
use function mb_strlen;
18
use function mb_strpos;
19
use function mb_strrpos;
20
use function mb_strtolower;
21
use function mb_strtoupper;
22
use function mb_strwidth;
23
use function mb_substr;
24
use function preg_match;
25
use function preg_quote;
26
use function preg_replace;
27
use function random_int;
28
use function rtrim;
29
use function str_pad;
30
use function str_replace;
31
use function strlen;
32
use function strncmp;
33
use function strpos;
34
use function strrpos;
35
use function substr;
36
use function substr_replace;
37
use function trim;
38
use function ucwords;
39
40
use const MB_CASE_TITLE;
41
use const STR_PAD_BOTH;
42
use const STR_PAD_LEFT;
43
use const STR_PAD_RIGHT;
44
45
class Strings
46
{
47
    /**
48
     * The cache for words.
49
     *
50
     * @var array
51
     */
52
    protected static $cache = [];
53
54
    /**
55
     * Removes any leading and traling slashes from a string.
56
     *
57
     * @param  string $string String with slashes
58
     */
59
    public static function trimSlashes(string $string): string
60
    {
61
        return static::trim($string, '/');
62
    }
63
64
    /**
65
     * Reduces multiple slashes in a string to single slashes.
66
     *
67
     * @param  string $string String or array of strings with slashes
68
     */
69
    public static function reduceSlashes(string $string): string
70
    {
71
        return preg_replace('#(?<!:)//+#', '/', $string);
72
    }
73
74
    /**
75
     * Removes single and double quotes from a string.
76
     *
77
     * @param  string $str String with single and double quotes
78
     */
79
    public static function stripQuotes(string $string): string
80
    {
81
        return str_replace(['"', "'"], '', $string);
82
    }
83
84
    /**
85
     * Convert single and double quotes to entities.
86
     *
87
     * @param  string $string String with single and double quotes
88
     */
89
    public static function quotesToEntities(string $string): string
0 ignored issues
show
Unused Code introduced by
The parameter $string is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

89
    public static function quotesToEntities(/** @scrutinizer ignore-unused */ string $string): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
90
    {
91
        return str_replace(["\'", '"', "'", '"'], ['&#39;', '&quot;', '&#39;', '&quot;'], $str);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $str seems to be never defined.
Loading history...
92
    }
93
94
    /**
95
     * Creates a random string of characters.
96
     *
97
     * @param  int    $length   The number of characters. Default is 16
98
     * @param  string $keyspace The keyspace
99
     */
100
    public static function random(int $length = 64, string $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'): string
101
    {
102
        if ($length <= 0) {
103
            $length = 1;
104
        }
105
106
        $pieces = [];
107
        $max    = static::length($keyspace, '8bit') - 1;
108
109
        for ($i = 0; $i < $length; ++$i) {
110
            $pieces[] = $keyspace[random_int(0, $max)];
111
        }
112
113
        return implode('', $pieces);
114
    }
115
116
    /**
117
     * Add's _1 to a string or increment the ending number to allow _2, _3, etc.
118
     *
119
     * @param  string $string    String to increment
120
     * @param  int    $first     Start with
121
     * @param  string $separator Separator
122
     */
123
    public static function increment(string $string, int $first = 1, string $separator = '_'): string
124
    {
125
        preg_match('/(.+)' . $separator . '([0-9]+)$/', $string, $match);
126
127
        return isset($match[2]) ? $match[1] . $separator . ($match[2] + 1) : $string . $separator . $first;
128
    }
129
130
    /**
131
     * Return the length of the given string.
132
     *
133
     * @param  string      $string   String to check
134
     * @param  string|null $encoding String encoding
135
     */
136
    public static function length(string $string, ?string $encoding = null): int
137
    {
138
        if ($encoding) {
139
            return mb_strlen($string, $encoding);
140
        }
141
142
        return mb_strlen($string);
143
    }
144
145
    /**
146
     * Limit the number of characters in a string.
147
     *
148
     * @param  string $string String
149
     * @param  int    $limit  Limit of characters
150
     * @param  string $append Text to append to the string IF it gets truncated
151
     */
152
    public static function limit(string $string, int $limit = 100, string $append = '...'): string
153
    {
154
        if (mb_strwidth($string, 'UTF-8') <= $limit) {
155
            return $string;
156
        }
157
158
        return rtrim(mb_strimwidth($string, 0, $limit, '', 'UTF-8')) . $append;
159
    }
160
161
    /**
162
     * Convert the given string to lower-case.
163
     *
164
     * @param  string $string String
165
     */
166
    public static function lower(string $string): string
167
    {
168
        return mb_strtolower($string, 'UTF-8');
169
    }
170
171
    /**
172
     * Convert the given string to upper-case.
173
     *
174
     * @param  string $value
175
     */
176
    public static function upper(string $string): string
177
    {
178
        return mb_strtoupper($string, 'UTF-8');
179
    }
180
181
    /**
182
     * Returns the portion of string specified by the start and length parameters.
183
     *
184
     * @param  string   $string The string to extract the substring from.
185
     * @param  int      $start  If start is non-negative, the returned string will
186
     *                          start at the start'th position in $string, counting from zero.
187
     *                          For instance, in the string 'abcdef', the character at position
188
     *                          0 is 'a', the character at position 2 is 'c', and so forth.
189
     * @param  int|null $length Maximum number of characters to use from string.
190
     *                          If omitted or NULL is passed, extract all characters to the end of the string.
191
     */
192
    public static function substr(string $string, int $start, ?int $length = null): string
193
    {
194
        return mb_substr($string, $start, $length, 'UTF-8');
195
    }
196
197
    /**
198
     * Convert a string to studly caps case.
199
     *
200
     * @param  string $string String
201
     */
202
    public static function studly(string $string): string
203
    {
204
        $key = $string;
205
206
        if (isset(static::$cache['studly'][$key])) {
207
            return static::$cache['studly'][$key];
208
        }
209
210
        $string = ucwords(str_replace(['-', '_'], ' ', $string));
211
212
        return static::$cache['studly'][$key] = str_replace(' ', '', $string);
213
    }
214
215
    /**
216
     * Convert a string to snake case.
217
     *
218
     * @param  string $string    String
219
     * @param  string $delimiter Delimeter
220
     */
221
    public static function snake(string $string, string $delimiter = '_'): string
222
    {
223
        $key = $string;
224
225
        if (isset(static::$cache['snake'][$key][$delimiter])) {
226
            return static::$cache['snake'][$key][$delimiter];
227
        }
228
229
        if (! ctype_lower($string)) {
230
            $value = preg_replace('/\s+/u', '', ucwords($string));
0 ignored issues
show
Unused Code introduced by
The assignment to $value is dead and can be removed.
Loading history...
231
232
            $string = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $string));
233
        }
234
235
        return static::$cache['snake'][$key][$delimiter] = $string;
236
    }
237
238
    /**
239
     * Convert a string to camel case.
240
     *
241
     * @param  string $string String
242
     */
243
    public static function camel(string $string): string
244
    {
245
        if (isset(static::$cache['camel'][$string])) {
246
            return static::$cache['camel'][$string];
247
        }
248
249
        return static::$cache['camel'][$string] = lcfirst(static::studly($string));
250
    }
251
252
    /**
253
     * Convert a string to kebab case.
254
     *
255
     * @param  string $string String
256
     */
257
    public static function kebab(string $string): string
258
    {
259
        return static::snake($string, '-');
260
    }
261
262
    /**
263
     * Limit the number of words in a string.
264
     *
265
     * @param  string $string String
266
     * @param  int    $words  Words limit
267
     * @param  string $append Text to append to the string IF it gets truncated
268
     */
269
    public static function words(string $string, int $words = 100, string $append = '...'): string
270
    {
271
        preg_match('/^\s*+(?:\S++\s*+){1,' . $words . '}/u', $string, $matches);
272
273
        if (! isset($matches[0]) || static::length($string) === static::length($matches[0])) {
274
            return $string;
275
        }
276
277
        return static::trimRight($matches[0]) . $append;
278
    }
279
280
    /**
281
     * Determine if a given string contains a given substring.
282
     *
283
     * @param  string          $haystack The string being checked.
284
     * @param  string|string[] $needles  The string to find in haystack.
285
     */
286
    public static function contains(string $haystack, $needles): bool
287
    {
288
        foreach ((array) $needles as $needle) {
289
            if ($needle !== '' && mb_strpos($haystack, $needle) !== false) {
290
                return true;
291
            }
292
        }
293
294
        return false;
295
    }
296
297
    /**
298
     * Determine if a given string contains all array values.
299
     *
300
     * @param  string   $haystack The string being checked.
301
     * @param  string[] $needles  The array of strings to find in haystack.
302
     */
303
    public static function containsAll(string $haystack, array $needles): bool
304
    {
305
        foreach ($needles as $needle) {
306
            if (! static::contains($haystack, $needle)) {
307
                return false;
308
            }
309
        }
310
311
        return true;
312
    }
313
314
    /**
315
     * Converts the first character of a string to upper case
316
     * and leaves the other characters unchanged.
317
     *
318
     * @param  string $string String
319
     */
320
    public static function ucfirst(string $string): string
321
    {
322
        return static::upper(static::substr($string, 0, 1)) . static::substr($string, 1);
323
    }
324
325
    /**
326
     * Converts the first character of every word of string to upper case and the others to lower case.
327
     *
328
     * @param  string $string String
329
     */
330
    public static function capitalize(string $string): string
331
    {
332
        return mb_convert_case($string, MB_CASE_TITLE, 'UTF-8');
333
    }
334
335
    /**
336
     * Strip whitespace (or other characters) from the beginning and end of a string.
337
     *
338
     * @param string $string         The string that will be trimmed.
339
     * @param string $character_mask Optionally, the stripped characters can also be
340
     *                               specified using the character_mask parameter..
341
     */
342
    public static function trim(string $string, string $character_mask = " \t\n\r\0\x0B"): string
343
    {
344
        return trim($string, $character_mask);
345
    }
346
347
    /**
348
     * Strip whitespace (or other characters) from the beginning of a string.
349
     *
350
     * @param string $string         The string that will be trimmed.
351
     * @param string $character_mask Optionally, the stripped characters can also be
352
     *                               specified using the character_mask parameter..
353
     */
354
    public static function trimLeft(string $string, string $character_mask = " \t\n\r\0\x0B"): string
355
    {
356
        return ltrim($string, $character_mask);
357
    }
358
359
    /**
360
     * Strip whitespace (or other characters) from the end of a string.
361
     *
362
     * @param string $string         The string that will be trimmed.
363
     * @param string $character_mask Optionally, the stripped characters can also be
364
     *                               specified using the character_mask parameter..
365
     */
366
    public static function trimRight(string $string, string $character_mask = " \t\n\r\0\x0B"): string
367
    {
368
        return rtrim($string, $character_mask);
369
    }
370
371
    /**
372
     * Reverses string.
373
     *
374
     * @param  string $string String
375
     */
376
    public static function reverse(string $string): string
377
    {
378
        $result = '';
379
380
        for ($i = static::length($string); $i >= 0; $i--) {
381
            $result .= static::substr($string, $i, 1);
382
        }
383
384
        return $result;
385
    }
386
387
    /**
388
     * Get a segment from a string based on a delimiter.
389
     * Returns an empty string when the offset doesn't exist.
390
     * Use a negative index to start counting from the last element.
391
     *
392
     * @param string $string    String
393
     * @param string $delimiter Delimeter
394
     * @param int    $index     Index
395
     */
396
    public function segment(string $string, int $index, string $delimiter = ' '): string
397
    {
398
        $segments = explode($delimiter, $string);
399
400
        if ($index < 0) {
401
            $segments = array_reverse($segments);
402
            $index    = abs($index) - 1;
403
        }
404
405
        return $segments[$index] ?? '';
406
    }
407
408
    /**
409
     * Get the first segment from a string based on a delimiter.
410
     *
411
     * @param string $string    String
412
     * @param string $delimiter Delimeter
413
     */
414
    public function firstSegment(string $string, string $delimiter = ' '): string
415
    {
416
        return static::segment($string, 0, $delimiter);
0 ignored issues
show
Bug Best Practice introduced by
The method Flextype\Component\Strings\Strings::segment() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

416
        return static::/** @scrutinizer ignore-call */ segment($string, 0, $delimiter);
Loading history...
417
    }
418
419
    /**
420
     * Get the last segment from a string based on a delimiter.
421
     *
422
     * @param string $string    String
423
     * @param string $delimiter Delimeter
424
     */
425
    public function lastSegment(string $string, string $delimiter = ' '): string
426
    {
427
        return static::segment($string, -1, $delimiter);
0 ignored issues
show
Bug Best Practice introduced by
The method Flextype\Component\Strings\Strings::segment() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

427
        return static::/** @scrutinizer ignore-call */ segment($string, -1, $delimiter);
Loading history...
428
    }
429
430
    /**
431
     * Get the portion of a string before the first occurrence of a given value.
432
     *
433
     * @param string $string String
434
     * @param string $search Search
435
     */
436
    public static function before(string $string, string $search): string
437
    {
438
        return $search === '' ? $string : explode($search, $string)[0];
439
    }
440
441
    /**
442
     * Get the portion of a string before the last occurrence of a given value.
443
     *
444
     * @param string $string String
445
     * @param string $search Search
446
     */
447
    public static function beforeLast(string $string, string $search): string
448
    {
449
        if ($search === '') {
450
            return $string;
451
        }
452
453
        $position = mb_strrpos($string, $search);
454
455
        if ($position === false) {
456
            return $string;
457
        }
458
459
        return static::substr($string, 0, $position);
460
    }
461
462
    /**
463
     * Return the remainder of a string after the first occurrence of a given value.
464
     *
465
     * @param string $string String
466
     * @param string $search Search
467
     */
468
    public static function after(string $string, string $search): string
469
    {
470
        return $search === '' ? $string : array_reverse(explode($search, $string, 2))[0];
471
    }
472
473
    /**
474
     * Return the remainder of a string after the last occurrence of a given value.
475
     *
476
     * @param string $string String
477
     * @param string $search Search
478
     */
479
    public static function afterLast(string $string, string $search): string
480
    {
481
        if ($search === '') {
482
            return $string;
483
        }
484
485
        $position = mb_strrpos($string, (string) $search);
486
487
        if ($position === false) {
488
            return $string;
489
        }
490
491
        return static::substr($string, $position + static::length($search));
492
    }
493
494
    /**
495
     * Pad both sides of a string with another.
496
     *
497
     * @param  string $string The input string.
498
     * @param  int    $length If the value of pad_length is negative, less than, or equal to the length of the input string, no padding takes place, and input will be returned.
499
     * @param  string $pad    The pad string may be truncated if the required number of padding characters can't be evenly divided by the pad_string's length.
500
     */
501
    public static function padBoth(string $string, int $length, string $pad = ' '): string
502
    {
503
        return str_pad($string, $length, $pad, STR_PAD_BOTH);
504
    }
505
506
    /**
507
     * Pad the left side of a string with another.
508
     *
509
     * @param  string $string The input string.
510
     * @param  int    $length If the value of pad_length is negative, less than, or equal to the length of the input string, no padding takes place, and input will be returned.
511
     * @param  string $pad    The pad string may be truncated if the required number of padding characters can't be evenly divided by the pad_string's length.
512
     */
513
    public static function padLeft(string $string, int $length, string $pad = ' '): string
514
    {
515
        return str_pad($string, $length, $pad, STR_PAD_LEFT);
516
    }
517
518
    /**
519
     * Pad the right side of a string with another.
520
     *
521
     * @param  string $string The input string.
522
     * @param  int    $length If the value of pad_length is negative, less than, or equal to the length of the input string, no padding takes place, and input will be returned.
523
     * @param  string $pad    The pad string may be truncated if the required number of padding characters can't be evenly divided by the pad_string's length.
524
     */
525
    public static function padRight(string $string, int $length, string $pad = ' '): string
526
    {
527
        return str_pad($string, $length, $pad, STR_PAD_RIGHT);
528
    }
529
530
    /**
531
     * Strip all whitespaces from the given string.
532
     *
533
     * @param string $string The string to strip
534
     */
535
    public static function stripSpaces(string $string): string
536
    {
537
        return preg_replace('/\s+/', '', $string);
538
    }
539
540
    /**
541
     * Replace a given value in the string sequentially with an array.
542
     *
543
     * @param  string $string  String
544
     * @param  string $search  Search
545
     * @param  array  $replace Replace
546
     */
547
    public static function replaceArray(string $string, string $search, array $replace): string
548
    {
549
        $segments = explode($search, $string);
550
551
        $result = array_shift($segments);
552
553
        foreach ($segments as $segment) {
554
            $result .= (array_shift($replace) ?? $search) . $segment;
555
        }
556
557
        return $result;
558
    }
559
560
    /**
561
     * Replace the first occurrence of a given value in the string.
562
     *
563
     * @param  string $string  String
564
     * @param  string $search  Search
565
     * @param  string $replace Replace
566
     */
567
    public static function replaceFirst(string $string, string $search, string $replace): string
568
    {
569
        if ($search === '') {
570
            return $string;
571
        }
572
573
        $position = strpos($string, $search);
574
575
        if ($position !== false) {
576
            return substr_replace($string, $replace, $position, strlen($search));
577
        }
578
579
        return $search;
580
    }
581
582
    /**
583
     * Replace the last occurrence of a given value in the string.
584
     *
585
     * @param  string $string  String
586
     * @param  string $search  Search
587
     * @param  string $replace Replace
588
     */
589
    public static function replaceLast(string $string, string $search, string $replace): string
590
    {
591
        $position = strrpos($string, $search);
592
593
        if ($position !== false) {
594
            return substr_replace($string, $replace, $position, strlen($search));
595
        }
596
597
        return $subject;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $subject seems to be never defined.
Loading history...
598
    }
599
600
    /**
601
     * Begin a string with a single instance of a given value.
602
     *
603
     * @param  string $string String
604
     * @param  string $prefix Prefix
605
     */
606
    public static function start(string $string, string $prefix): string
607
    {
608
        $quoted = preg_quote($prefix, '/');
609
610
        return $prefix . preg_replace('/^(?:' . $quoted . ')+/u', '', $string);
611
    }
612
613
    /**
614
     * Determine if a given string starts with a given substring.
615
     *
616
     * @param  string          $haystack Haystack
617
     * @param  string|string[] $needles  needles
618
     */
619
    public static function startsWith(string $haystack, $needles): bool
620
    {
621
        foreach ((array) $needles as $needle) {
622
            if ((string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0) {
623
                return true;
624
            }
625
        }
626
627
        return false;
628
    }
629
630
    /**
631
     * Determine if a given string ends with a given substring.
632
     *
633
     * @param  string          $haystack Haystack
634
     * @param  string|string[] $needles  needles
635
     */
636
    public static function endsWith(string $haystack, $needles): bool
637
    {
638
        foreach ((array) $needles as $needle) {
639
            if ($needle !== '' && substr($haystack, -strlen($needle)) === (string) $needle) {
640
                return true;
641
            }
642
        }
643
644
        return false;
645
    }
646
647
    /**
648
     * Cap a string with a single instance of a given value.
649
     *
650
     * @param  string $string String
651
     * @param  string $cap    Cap
652
     */
653
    public static function finish(string $string, string $cap): string
654
    {
655
        $quoted = preg_quote($cap, '/');
656
657
        return preg_replace('/(?:' . $quoted . ')+$/u', '', $string) . $cap;
658
    }
659
}
660