Completed
Push — master ( e1255d...678b0e )
by Antonio Carlos
02:36 queued 59s
created

Str::containsAll()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 10
ccs 5
cts 5
cp 1
crap 3
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace IlluminateAgnostic\Str\Support;
4
5
use Ramsey\Uuid\Uuid;
6
use Ramsey\Uuid\UuidFactory;
7
use IlluminateAgnostic\Str\Support\Traits\Macroable;
8
use Ramsey\Uuid\Generator\CombGenerator;
9
use Ramsey\Uuid\Codec\TimestampFirstCombCodec;
10
11
class Str
12
{
13
    use Macroable;
14
15
    /**
16
     * The cache of snake-cased words.
17
     *
18
     * @var array
19
     */
20
    protected static $snakeCache = [];
21
22
    /**
23
     * The cache of camel-cased words.
24
     *
25
     * @var array
26
     */
27
    protected static $camelCache = [];
28
29
    /**
30
     * The cache of studly-cased words.
31
     *
32
     * @var array
33
     */
34
    protected static $studlyCache = [];
35
36
    /**
37
     * Return the remainder of a string after a given value.
38
     *
39
     * @param  string  $subject
40
     * @param  string  $search
41
     * @return string
42
     */
43 1
    public static function after($subject, $search)
44
    {
45 1
        return $search === '' ? $subject : array_reverse(explode($search, $subject, 2))[0];
46
    }
47
48
    /**
49
     * Transliterate a UTF-8 value to ASCII.
50
     *
51
     * @param  string  $value
52
     * @param  string  $language
53
     * @return string
54
     */
55 3
    public static function ascii($value, $language = 'en')
56
    {
57 3
        $languageSpecific = static::languageSpecificCharsArray($language);
58
59 3
        if (! is_null($languageSpecific)) {
60 1
            $value = str_replace($languageSpecific[0], $languageSpecific[1], $value);
61
        }
62
63 3
        foreach (static::charsArray() as $key => $val) {
64 3
            $value = str_replace($val, $key, $value);
65
        }
66
67 3
        return preg_replace('/[^\x20-\x7E]/u', '', $value);
68
    }
69
70
    /**
71
     * Get the portion of a string before a given value.
72
     *
73
     * @param  string  $subject
74
     * @param  string  $search
75
     * @return string
76
     */
77 1
    public static function before($subject, $search)
78
    {
79 1
        return $search === '' ? $subject : explode($search, $subject)[0];
80
    }
81
82
    /**
83
     * Convert a value to camel case.
84
     *
85
     * @param  string  $value
86
     * @return string
87
     */
88 2
    public static function camel($value)
89
    {
90 2
        if (isset(static::$camelCache[$value])) {
91 2
            return static::$camelCache[$value];
92
        }
93
94 2
        return static::$camelCache[$value] = lcfirst(static::studly($value));
95
    }
96
97
    /**
98
     * Determine if a given string contains a given substring.
99
     *
100
     * @param  string  $haystack
101
     * @param  string|array  $needles
102
     * @return bool
103
     */
104 2
    public static function contains($haystack, $needles)
105
    {
106 2
        foreach ((array) $needles as $needle) {
107 2
            if ($needle !== '' && mb_strpos($haystack, $needle) !== false) {
108 2
                return true;
109
            }
110
        }
111
112 2
        return false;
113
    }
114
115
    /**
116
     * Determine if a given string contains all array values.
117
     *
118
     * @param  string  $haystack
119
     * @param  array  $needles
120
     * @return bool
121
     */
122 1
    public static function containsAll($haystack, array $needles)
123
    {
124 1
        foreach ($needles as $needle) {
125 1
            if (! static::contains($haystack, $needle)) {
126 1
                return false;
127
            }
128
        }
129
130 1
        return true;
131
    }
132
133
    /**
134
     * Determine if a given string ends with a given substring.
135
     *
136
     * @param  string  $haystack
137
     * @param  string|array  $needles
138
     * @return bool
139
     */
140 1 View Code Duplication
    public static function endsWith($haystack, $needles)
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...
141
    {
142 1
        foreach ((array) $needles as $needle) {
143
            if (substr($haystack, -strlen($needle)) === (string) $needle) {
144 1
                return true;
145
            }
146
        }
147
148
        return false;
149
    }
150
151
    /**
152
     * Cap a string with a single instance of a given value.
153
     *
154 2
     * @param  string  $value
155
     * @param  string  $cap
156 2
     * @return string
157
     */
158 2
    public static function finish($value, $cap)
159 1
    {
160
        $quoted = preg_quote($cap, '/');
161
162 1
        return preg_replace('/(?:'.$quoted.')+$/u', '', $value).$cap;
163
    }
164
165
    /**
166 1
     * Determine if a given string matches a given pattern.
167 1
     *
168
     * @param  string|array  $pattern
169
     * @param  string  $value
170 1
     * @return bool
171
     */
172
    public static function is($pattern, $value)
173
    {
174
        $patterns = Arr::wrap($pattern);
175 1
176
        if (empty($patterns)) {
177 1
            return false;
178 1
        }
179
180
        foreach ($patterns as $pattern) {
181
            // If the given value is an exact match we can of course return true right
182 1
            // from the beginning. Otherwise, we will translate asterisks and do an
183
            // actual pattern match against the two strings to see if they match.
184
            if ($pattern == $value) {
185
                return true;
186
            }
187
188
            $pattern = preg_quote($pattern, '#');
189
190
            // Asterisks are translated into zero-or-more regular expression wildcards
191 1
            // to make it convenient to check if the strings starts with the given
192
            // pattern such as "library/*", making any string check convenient.
193 1
            $pattern = str_replace('\*', '.*', $pattern);
194
195
            if (preg_match('#^'.$pattern.'\z#u', $value) === 1) {
196
                return true;
197
            }
198
        }
199
200
        return false;
201
    }
202
203 4
    /**
204
     * Convert a string to kebab case.
205 4
     *
206 1
     * @param  string  $value
207
     * @return string
208
     */
209 4
    public static function kebab($value)
210
    {
211
        return static::snake($value, '-');
212
    }
213
214
    /**
215
     * Return the length of the given string.
216
     *
217
     * @param  string  $value
218
     * @param  string  $encoding
219
     * @return int
220 2
     */
221
    public static function length($value, $encoding = null)
222 2
    {
223 2
        if ($encoding) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $encoding of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
224
            return mb_strlen($value, $encoding);
225
        }
226 1
227
        return mb_strlen($value);
228
    }
229
230
    /**
231
     * Limit the number of characters in a string.
232
     *
233
     * @param  string  $value
234
     * @param  int     $limit
235 5
     * @param  string  $end
236
     * @return string
237 5
     */
238
    public static function limit($value, $limit = 100, $end = '...')
239
    {
240
        if (mb_strwidth($value, 'UTF-8') <= $limit) {
241
            return $value;
242
        }
243
244
        return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')).$end;
245
    }
246
247
    /**
248 3
     * Convert the given string to lower-case.
249
     *
250 3
     * @param  string  $value
251
     * @return string
252 3
     */
253 3
    public static function lower($value)
254
    {
255
        return mb_strtolower($value, 'UTF-8');
256 2
    }
257
258
    /**
259
     * Limit the number of words in a string.
260
     *
261
     * @param  string  $value
262
     * @param  int     $words
263
     * @param  string  $end
264
     * @return string
265
     */
266 1
    public static function words($value, $words = 100, $end = '...')
267
    {
268 1
        preg_match('/^\s*+(?:\S++\s*+){1,'.$words.'}/u', $value, $matches);
269
270
        if (! isset($matches[0]) || static::length($value) === static::length($matches[0])) {
271
            return $value;
272
        }
273
274
        return rtrim($matches[0]).$end;
275
    }
276
277
    /**
278 1
     * Parse a Class@method style callback into class and method.
279
     *
280 1
     * @param  string  $callback
281
     * @param  string|null  $default
282
     * @return array
283
     */
284
    public static function parseCallback($callback, $default = null)
285
    {
286
        return static::contains($callback, '@') ? explode('@', $callback, 2) : [$callback, $default];
287
    }
288
289
    /**
290
     * Get the plural form of an English word.
291
     *
292
     * @param  string  $value
293
     * @param  int     $count
294
     * @return string
295
     */
296
    public static function plural($value, $count = 2)
297
    {
298
        return Pluralizer::plural($value, $count);
299
    }
300
301
    /**
302
     * Pluralize the last word of an English, studly caps case string.
303
     *
304
     * @param  string  $value
305 1
     * @param  int     $count
306
     * @return string
307 1
     */
308
    public static function pluralStudly($value, $count = 2)
309 1
    {
310 1
        $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE);
311
312 1
        $lastWord = array_pop($parts);
313
314 1
        return implode('', $parts).self::plural($lastWord, $count);
315
    }
316
317 1
    /**
318
     * Generate a more truly "random" alpha-numeric string.
319
     *
320
     * @param  int  $length
321
     * @return string
322
     */
323
    public static function random($length = 16)
324
    {
325
        $string = '';
326
327
        while (($len = strlen($string)) < $length) {
328 1
            $size = $length - $len;
329
330 1
            $bytes = random_bytes($size);
331 1
332
            $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
333
        }
334 1
335
        return $string;
336
    }
337
338
    /**
339
     * Replace a given value in the string sequentially with an array.
340
     *
341
     * @param  string  $search
342
     * @param  array   $replace
343
     * @param  string  $subject
344
     * @return string
345 2
     */
346
    public static function replaceArray($search, array $replace, $subject)
347 2
    {
348 1
        $segments = explode($search, $subject);
349
350
        $result = array_shift($segments);
351 2
352
        foreach ($segments as $segment) {
353 2
            $result .= (array_shift($replace) ?? $search).$segment;
354 2
        }
355
356
        return $result;
357 2
    }
358
359
    /**
360
     * Replace the first occurrence of a given value in the string.
361
     *
362
     * @param  string  $search
363
     * @param  string  $replace
364
     * @param  string  $subject
365
     * @return string
366
     */
367 View Code Duplication
    public static function replaceFirst($search, $replace, $subject)
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...
368 1
    {
369
        if ($search == '') {
370 1
            return $subject;
371
        }
372 1
373 1
        $position = strpos($subject, $search);
374
375
        if ($position !== false) {
376 1
            return substr_replace($subject, $replace, $position, strlen($search));
377
        }
378
379
        return $subject;
380
    }
381
382
    /**
383
     * Replace the last occurrence of a given value in the string.
384
     *
385
     * @param  string  $search
386 2
     * @param  string  $replace
387
     * @param  string  $subject
388 2
     * @return string
389
     */
390 2 View Code Duplication
    public static function replaceLast($search, $replace, $subject)
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...
391
    {
392
        $position = strrpos($subject, $search);
393
394
        if ($position !== false) {
395
            return substr_replace($subject, $replace, $position, strlen($search));
396
        }
397
398
        return $subject;
399 2
    }
400
401 2
    /**
402
     * Begin a string with a single instance of a given value.
403
     *
404
     * @param  string  $value
405
     * @param  string  $prefix
406
     * @return string
407
     */
408
    public static function start($value, $prefix)
409
    {
410 1
        $quoted = preg_quote($prefix, '/');
411
412 1
        return $prefix.preg_replace('/^(?:'.$quoted.')+/u', '', $value);
413
    }
414
415
    /**
416
     * Convert the given string to upper-case.
417
     *
418
     * @param  string  $value
419
     * @return string
420
     */
421 1
    public static function upper($value)
422
    {
423 1
        return mb_strtoupper($value, 'UTF-8');
424
    }
425
426
    /**
427
     * Convert the given string to title case.
428
     *
429
     * @param  string  $value
430
     * @return string
431
     */
432
    public static function title($value)
433
    {
434 1
        return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');
435
    }
436 1
437
    /**
438
     * Get the singular form of an English word.
439 1
     *
440
     * @param  string  $value
441 1
     * @return string
442
     */
443
    public static function singular($value)
444 1
    {
445
        return Pluralizer::singular($value);
446
    }
447 1
448
    /**
449
     * Generate a URL friendly "slug" from a given string.
450 1
     *
451
     * @param  string  $title
452 1
     * @param  string  $separator
453
     * @param  string|null  $language
454
     * @return string
455
     */
456
    public static function slug($title, $separator = '-', $language = 'en')
457
    {
458
        $title = $language ? static::ascii($title, $language) : $title;
459
460
        // Convert all dashes/underscores into separator
461
        $flip = $separator === '-' ? '_' : '-';
462 3
463
        $title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title);
464 3
465
        // Replace @ with the word 'at'
466 3
        $title = str_replace('@', $separator.'at'.$separator, $title);
467 1
468
        // Remove all characters that are not the separator, letters, numbers, or whitespace.
469
        $title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', static::lower($title));
470 3
471 3
        // Replace all separator characters and whitespace by a single separator
472
        $title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title);
473 3
474
        return trim($title, $separator);
475
    }
476 3
477
    /**
478
     * Convert a string to snake case.
479
     *
480
     * @param  string  $value
481
     * @param  string  $delimiter
482
     * @return string
483
     */
484
    public static function snake($value, $delimiter = '_')
485
    {
486 1
        $key = $value;
487
488 1
        if (isset(static::$snakeCache[$key][$delimiter])) {
489 1
            return static::$snakeCache[$key][$delimiter];
490 1
        }
491
492
        if (! ctype_lower($value)) {
493
            $value = preg_replace('/\s+/u', '', ucwords($value));
494 1
495
            $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value));
496
        }
497
498
        return static::$snakeCache[$key][$delimiter] = $value;
499
    }
500
501
    /**
502
     * Determine if a given string starts with a given substring.
503 3
     *
504
     * @param  string  $haystack
505 3
     * @param  string|array  $needles
506
     * @return bool
507 3
     */
508 3 View Code Duplication
    public static function startsWith($haystack, $needles)
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...
509
    {
510
        foreach ((array) $needles as $needle) {
511 3
            if ($needle !== '' && substr($haystack, 0, strlen($needle)) === (string) $needle) {
512
                return true;
513 3
            }
514
        }
515
516
        return false;
517
    }
518
519
    /**
520
     * Convert a value to studly caps case.
521
     *
522
     * @param  string  $value
523
     * @return string
524 2
     */
525
    public static function studly($value)
526 2
    {
527
        $key = $value;
528
529
        if (isset(static::$studlyCache[$key])) {
530
            return static::$studlyCache[$key];
531
        }
532
533
        $value = ucwords(str_replace(['-', '_'], ' ', $value));
534
535 1
        return static::$studlyCache[$key] = str_replace(' ', '', $value);
536
    }
537 1
538
    /**
539
     * Returns the portion of string specified by the start and length parameters.
540
     *
541
     * @param  string  $string
542
     * @param  int  $start
543
     * @param  int|null  $length
544
     * @return string
545 1
     */
546
    public static function substr($string, $start, $length = null)
547 1
    {
548
        return mb_substr($string, $start, $length, 'UTF-8');
549
    }
550
551
    /**
552
     * Make a string's first character uppercase.
553
     *
554
     * @param  string  $string
555 1
     * @return string
556
     */
557 1
    public static function ucfirst($string)
558
    {
559 1
        return static::upper(static::substr($string, 0, 1)).static::substr($string, 1);
560 1
    }
561 1
562
    /**
563
     * Generate a UUID (version 4).
564 1
     *
565 1
     * @return \Ramsey\Uuid\UuidInterface
566
     */
567
    public static function uuid()
568 1
    {
569
        return Uuid::uuid4();
570
    }
571
572
    /**
573
     * Generate a time-ordered UUID (version 4).
574
     *
575
     * @return \Ramsey\Uuid\UuidInterface
576
     */
577
    public static function orderedUuid()
578
    {
579
        $factory = new UuidFactory;
580 3
581
        $factory->setRandomGenerator(new CombGenerator(
582 3
            $factory->getRandomGenerator(),
583
            $factory->getNumberConverter()
584 3
        ));
585 3
586
        $factory->setCodec(new TimestampFirstCombCodec(
587
            $factory->getUuidBuilder()
588
        ));
589 1
590
        return $factory->uuid4();
591
    }
592
593
    /**
594
     * Returns the replacements for the ascii method.
595
     *
596
     * Note: Adapted from Stringy\Stringy.
597
     *
598
     * @see https://github.com/danielstjules/Stringy/blob/3.1.0/LICENSE.txt
599
     *
600
     * @return array
601
     */
602
    protected static function charsArray()
603
    {
604
        static $charsArray;
605
606
        if (isset($charsArray)) {
607
            return $charsArray;
608
        }
609
610
        return $charsArray = [
611
            '0'    => ['°', '₀', '۰', '0'],
612
            '1'    => ['¹', '₁', '۱', '1'],
613
            '2'    => ['²', '₂', '۲', '2'],
614
            '3'    => ['³', '₃', '۳', '3'],
615
            '4'    => ['⁴', '₄', '۴', '٤', '4'],
616
            '5'    => ['⁵', '₅', '۵', '٥', '5'],
617
            '6'    => ['⁶', '₆', '۶', '٦', '6'],
618
            '7'    => ['⁷', '₇', '۷', '7'],
619
            '8'    => ['⁸', '₈', '۸', '8'],
620
            '9'    => ['⁹', '₉', '۹', '9'],
621
            'a'    => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ', 'ặ', 'â', 'ấ', 'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å', 'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', 'ἄ', 'ἅ', 'ἆ', 'ἇ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ', 'ά', 'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ', 'အ', 'ာ', 'ါ', 'ǻ', 'ǎ', 'ª', 'ა', 'अ', 'ا', 'a', 'ä', 'א'],
622
            'b'    => ['б', 'β', 'ب', 'ဗ', 'ბ', 'b', 'ב'],
623
            'c'    => ['ç', 'ć', 'č', 'ĉ', 'ċ', 'c'],
624
            'd'    => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ', 'д', 'δ', 'د', 'ض', 'ဍ', 'ဒ', 'დ', 'd', 'ד'],
625
            'e'    => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ', 'ệ', 'ë', 'ē', 'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ', 'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', 'έ', 'е', 'ё', 'э', 'є', 'ə', 'ဧ', 'ေ', 'ဲ', 'ე', 'ए', 'إ', 'ئ', 'e'],
626
            'f'    => ['ф', 'φ', 'ف', 'ƒ', 'ფ', 'f', 'פ', 'ף'],
627
            'g'    => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ဂ', 'გ', 'گ', 'g', 'ג'],
628
            'h'    => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ', 'h', 'ה'],
629
            'i'    => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į', 'ı', 'ι', 'ί', 'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ', 'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', 'ῑ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'і', 'ї', 'и', 'ဣ', 'ိ', 'ီ', 'ည်', 'ǐ', 'ი', 'इ', 'ی', 'i', 'י'],
630
            'j'    => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج', 'j'],
631
            'k'    => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك', 'က', 'კ', 'ქ', 'ک', 'k', 'ק'],
632
            'l'    => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ', 'l', 'ל'],
633
            'm'    => ['м', 'μ', 'م', 'မ', 'მ', 'm', 'מ', 'ם'],
634
            'n'    => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن', 'န', 'ნ', 'n', 'נ'],
635
            'o'    => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ', 'ộ', 'ơ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő', 'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', 'ὄ', 'ὅ', 'ὸ', 'ό', 'о', 'و', 'ို', 'ǒ', 'ǿ', 'º', 'ო', 'ओ', 'o', 'ö'],
636
            'p'    => ['п', 'π', 'ပ', 'პ', 'پ', 'p', 'פ', 'ף'],
637
            'q'    => ['ყ', 'q'],
638
            'r'    => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ', 'r', 'ר'],
639
            's'    => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص', 'စ', 'ſ', 'ს', 's', 'ס'],
640
            't'    => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط', 'ဋ', 'တ', 'ŧ', 'თ', 'ტ', 't', 'ת'],
641
            'u'    => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ', 'ự', 'û', 'ū', 'ů', 'ű', 'ŭ', 'ų', 'µ', 'у', 'ဉ', 'ု', 'ူ', 'ǔ', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'უ', 'उ', 'u', 'ў', 'ü'],
642
            'v'    => ['в', 'ვ', 'ϐ', 'v', 'ו'],
643
            'w'    => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ', 'w'],
644
            'x'    => ['χ', 'ξ', 'x'],
645
            'y'    => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ', 'ϋ', 'ύ', 'ΰ', 'ي', 'ယ', 'y'],
646
            'z'    => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ', 'z', 'ז'],
647
            'aa'   => ['ع', 'आ', 'آ'],
648
            'ae'   => ['æ', 'ǽ'],
649
            'ai'   => ['ऐ'],
650
            'ch'   => ['ч', 'ჩ', 'ჭ', 'چ'],
651
            'dj'   => ['ђ', 'đ'],
652
            'dz'   => ['џ', 'ძ', 'דז'],
653
            'ei'   => ['ऍ'],
654
            'gh'   => ['غ', 'ღ'],
655
            'ii'   => ['ई'],
656
            'ij'   => ['ij'],
657
            'kh'   => ['х', 'خ', 'ხ'],
658
            'lj'   => ['љ'],
659
            'nj'   => ['њ'],
660
            'oe'   => ['ö', 'œ', 'ؤ'],
661
            'oi'   => ['ऑ'],
662
            'oii'  => ['ऒ'],
663
            'ps'   => ['ψ'],
664
            'sh'   => ['ш', 'შ', 'ش', 'ש'],
665
            'shch' => ['щ'],
666
            'ss'   => ['ß'],
667
            'sx'   => ['ŝ'],
668
            'th'   => ['þ', 'ϑ', 'θ', 'ث', 'ذ', 'ظ'],
669
            'ts'   => ['ц', 'ც', 'წ'],
670
            'ue'   => ['ü'],
671
            'uu'   => ['ऊ'],
672
            'ya'   => ['я'],
673
            'yu'   => ['ю'],
674
            'zh'   => ['ж', 'ჟ', 'ژ'],
675
            '(c)'  => ['©'],
676
            'A'    => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ', 'Ặ', 'Â', 'Ấ', 'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą', 'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', 'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ', 'Ᾱ', 'Ὰ', 'Ά', 'ᾼ', 'А', 'Ǻ', 'Ǎ', 'A', 'Ä'],
677
            'B'    => ['Б', 'Β', 'ब', 'B'],
678
            'C'    => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ', 'C'],
679
            'D'    => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ', 'D'],
680
            'E'    => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ', 'Ệ', 'Ë', 'Ē', 'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ', 'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', 'Ὲ', 'Е', 'Ё', 'Э', 'Є', 'Ə', 'E'],
681
            'F'    => ['Ф', 'Φ', 'F'],
682
            'G'    => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ', 'G'],
683
            'H'    => ['Η', 'Ή', 'Ħ', 'H'],
684
            'I'    => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į', 'İ', 'Ι', 'Ί', 'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ', 'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', 'І', 'Ї', 'Ǐ', 'ϒ', 'I'],
685
            'J'    => ['J'],
686
            'K'    => ['К', 'Κ', 'K'],
687
            'L'    => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल', 'L'],
688
            'M'    => ['М', 'Μ', 'M'],
689
            'N'    => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν', 'N'],
690
            'O'    => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ', 'Ộ', 'Ơ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő', 'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', 'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ', 'Ό', 'О', 'Ө', 'Ǒ', 'Ǿ', 'O', 'Ö'],
691
            'P'    => ['П', 'Π', 'P'],
692
            'Q'    => ['Q'],
693
            'R'    => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ', 'R'],
694
            'S'    => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ', 'S'],
695
            'T'    => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ', 'T'],
696
            'U'    => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ', 'Ự', 'Û', 'Ū', 'Ů', 'Ű', 'Ŭ', 'Ų', 'У', 'Ǔ', 'Ǖ', 'Ǘ', 'Ǚ', 'Ǜ', 'U', 'Ў', 'Ü'],
697
            'V'    => ['В', 'V'],
698
            'W'    => ['Ω', 'Ώ', 'Ŵ', 'W'],
699
            'X'    => ['Χ', 'Ξ', 'X'],
700
            'Y'    => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ', 'Ы', 'Й', 'Υ', 'Ϋ', 'Ŷ', 'Y'],
701
            'Z'    => ['Ź', 'Ž', 'Ż', 'З', 'Ζ', 'Z'],
702
            'AE'   => ['Æ', 'Ǽ'],
703
            'Ch'   => ['Ч'],
704
            'Dj'   => ['Ђ'],
705
            'Dz'   => ['Џ'],
706
            'Gx'   => ['Ĝ'],
707
            'Hx'   => ['Ĥ'],
708
            'Ij'   => ['IJ'],
709
            'Jx'   => ['Ĵ'],
710
            'Kh'   => ['Х'],
711
            'Lj'   => ['Љ'],
712
            'Nj'   => ['Њ'],
713
            'Oe'   => ['Œ'],
714
            'Ps'   => ['Ψ'],
715 3
            'Sh'   => ['Ш', 'ש'],
716
            'Shch' => ['Щ'],
717 3
            'Ss'   => ['ẞ'],
718
            'Th'   => ['Þ', 'Θ', 'ת'],
719 3
            'Ts'   => ['Ц'],
720
            'Ya'   => ['Я', 'יא'],
721 1
            'Yu'   => ['Ю', 'יו'],
722
            'Zh'   => ['Ж'],
723
            ' '    => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80", "\xEF\xBE\xA0"],
724
        ];
725
    }
726
727
    /**
728
     * Returns the language specific replacements for the ascii method.
729
     *
730
     * Note: Adapted from Stringy\Stringy.
731
     *
732
     * @see https://github.com/danielstjules/Stringy/blob/3.1.0/LICENSE.txt
733
     *
734
     * @param  string  $language
735
     * @return array|null
736
     */
737
    protected static function languageSpecificCharsArray($language)
738
    {
739
        static $languageSpecific;
740 3
741
        if (! isset($languageSpecific)) {
742
            $languageSpecific = [
743
                'bg' => [
744
                    ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'],
745
                    ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'],
746
                ],
747
                'da' => [
748
                    ['æ', 'ø', 'å', 'Æ', 'Ø', 'Å'],
749
                    ['ae', 'oe', 'aa', 'Ae', 'Oe', 'Aa'],
750
                ],
751
                'de' => [
752
                    ['ä',  'ö',  'ü',  'Ä',  'Ö',  'Ü'],
753
                    ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'],
754
                ],
755
                'he' => [
756
                    ['א', 'ב', 'ג', 'ד', 'ה', 'ו'],
757
                    ['ז', 'ח', 'ט', 'י', 'כ', 'ל'],
758
                    ['מ', 'נ', 'ס', 'ע', 'פ', 'צ'],
759
                    ['ק', 'ר', 'ש', 'ת', 'ן', 'ץ', 'ך', 'ם', 'ף'],
760
                ],
761
                'ro' => [
762
                    ['ă', 'â', 'î', 'ș', 'ț', 'Ă', 'Â', 'Î', 'Ș', 'Ț'],
763
                    ['a', 'a', 'i', 's', 't', 'A', 'A', 'I', 'S', 'T'],
764
                ],
765
            ];
766
        }
767
768
        return $languageSpecific[$language] ?? null;
769
    }
770
}
771