Completed
Push — master ( 3f8089...580f83 )
by Antonio Carlos
06:32
created

Str::orderedUuid()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

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