Completed
Push — master ( 678b0e...adee67 )
by Antonio Carlos
01:52
created

Str::lower()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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