Passed
Push — develop ( c09191...4b5082 )
by nguereza
02:18
created

Str::padLeft()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 3
dl 0
loc 6
rs 10
1
<?php
2
3
/**
4
 * Platine Stdlib
5
 *
6
 * Platine Stdlib is a the collection of frequently used php features
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine Stdlib
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a copy
13
 * of this software and associated documentation files (the "Software"), to deal
14
 * in the Software without restriction, including without limitation the rights
15
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 * copies of the Software, and to permit persons to whom the Software is
17
 * furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in all
20
 * copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
 * SOFTWARE.
29
 */
30
31
/**
32
 *  @file Str.php
33
 *
34
 *  The String helper class
35
 *
36
 *  @package    Platine\Stdlib\Helper
37
 *  @author Platine Developers Team
38
 *  @copyright  Copyright (c) 2020
39
 *  @license    http://opensource.org/licenses/MIT  MIT License
40
 *  @link   http://www.iacademy.cf
41
 *  @version 1.0.0
42
 *  @filesource
43
 */
44
45
declare(strict_types=1);
46
47
namespace Platine\Stdlib\Helper;
48
49
/**
50
 * Class Str
51
 * @package Platine\Stdlib\Helper
52
 */
53
class Str
54
{
55
56
    /**
57
     * The cache of snake-cased words.
58
     *
59
     * @var array<string, string>
60
     */
61
    protected static array $snakeCache = [];
62
63
    /**
64
     * The cache of camel-cased words.
65
     *
66
     * @var array<string, string>
67
     */
68
    protected static array $camelCache = [];
69
70
    /**
71
     * The cache of studly-cased words.
72
     *
73
     * @var array<string, string>
74
     */
75
    protected static array $studlyCache = [];
76
77
    /**
78
     * Convert an UTF-8 value to ASCII.
79
     * @param string $value
80
     * @return string
81
     */
82
    public static function toAscii(string $value): string
83
    {
84
        foreach (self::getChars() as $key => $val) {
85
            $value = str_replace($val, $key, $value);
86
        }
87
88
        return (string)preg_replace('/[^\x20-\x7E]/u', '', $value);
89
    }
90
91
    /**
92
     * Convert to camel case
93
     * @param string $value
94
     * @param bool $lcfirst
95
     * @return string
96
     */
97
    public static function camel(string $value, bool $lcfirst = true): string
98
    {
99
        if (isset(self::$camelCache[$value])) {
100
            return self::$camelCache[$value];
101
        }
102
103
        $studly = static::studly($value);
104
        return self::$camelCache[$value] = ($lcfirst ? lcfirst($studly) : $studly);
105
    }
106
107
    /**
108
     * Convert an string to array
109
     * @param string $value
110
     * @param string $delimiter
111
     * @param int $limit
112
     * @return array<string>
113
     */
114
    public static function toArray(string $value, string $delimiter = ', ', int $limit = 0): array
115
    {
116
        $string = trim($value, $delimiter . ' ');
117
        if ($string === '') {
118
            return [];
119
        }
120
121
        $values = [];
122
        /** @var array<string> $rawList */
123
        $rawList = $limit < 1
124
                ? (array) explode($delimiter, $string)
125
                : (array) explode($delimiter, $string, $limit);
126
127
        foreach ($rawList as $val) {
128
            $val = trim($val);
129
            if ($val !== '') {
130
                $values[] = $val;
131
            }
132
        }
133
134
        return $values;
135
    }
136
137
    /**
138
     * Determine if a given string contains a given sub string.
139
     * @param string $value
140
     * @param string|array<mixed> $needles
141
     * @return bool
142
     */
143
    public static function contains(string $value, $needles): bool
144
    {
145
        if (!is_array($needles)) {
146
            $needles = [$needles];
147
        }
148
149
        foreach ($needles as $needle) {
150
            if ($needle !== '' && strpos($needle, $value) !== false) {
151
                return true;
152
            }
153
        }
154
155
        return false;
156
    }
157
158
    /**
159
     * Determine if a given string ends with a given sub string.
160
     * @param string $value
161
     * @param string|array<mixed> $needles
162
     * @return bool
163
     */
164
    public static function endsWith(string $value, $needles): bool
165
    {
166
        if (!is_array($needles)) {
167
            $needles = [$needles];
168
        }
169
170
        foreach ($needles as $needle) {
171
            if ($value === (string) substr($needle, -strlen($value))) {
172
                return true;
173
            }
174
        }
175
176
        return false;
177
    }
178
179
    /**
180
     * Determine if a given string starts with a given sub string.
181
     * @param string $value
182
     * @param string|array<mixed> $needles
183
     * @return bool
184
     */
185
    public static function startsWith(string $value, $needles): bool
186
    {
187
        if (!is_array($needles)) {
188
            $needles = [$needles];
189
        }
190
191
        foreach ($needles as $needle) {
192
            if ($needle !== '' && strpos($needle, $value) === 0) {
193
                return true;
194
            }
195
        }
196
197
        return false;
198
    }
199
200
    /**
201
     * Return the first line of multi line string
202
     * @param string $value
203
     * @return string
204
     */
205
    public static function firstLine(string $value): string
206
    {
207
        $str = trim($value);
208
209
        if ($str === '') {
210
            return '';
211
        }
212
213
        if (strpos($str, "\n") > 0) {
214
            $parts = explode("\n", $str);
215
216
            return $parts[0] ?? '';
217
        }
218
219
        return $str;
220
    }
221
222
    /**
223
     * Cap a string with a single instance of a given value.
224
     * @param string $value
225
     * @param string $cap
226
     * @return string
227
     */
228
    public static function finish(string $value, string $cap): string
229
    {
230
        $quoted = preg_quote($cap, '/');
231
232
        return (string) preg_replace('/(?:' . $quoted . ')+$/', '', $value)
233
                . $cap;
234
    }
235
236
    /**
237
     * Determine if a given string matches a given pattern.
238
     * @param string $pattern
239
     * @param string $value
240
     * @return bool
241
     */
242
    public static function is(string $pattern, string $value): bool
243
    {
244
        if ($pattern === $value) {
245
            return true;
246
        }
247
248
        $quoted = preg_quote($pattern, '#');
249
250
        // Asterisks are translated into zero-or-more regular expression wildcards
251
        // to make it convenient to check if the strings starts with the given
252
        // pattern such as "library/*", making any string check convenient.
253
        $cleanQuoted = str_replace('\*', '.*', $quoted);
254
255
        return (bool)preg_match('#^' . $cleanQuoted . '\z#', $value);
256
    }
257
258
    /**
259
     * Return the length of the given string
260
     * @param string|int $value
261
     * @param string $encode
262
     * @return int
263
     */
264
    public static function length($value, string $encode = 'UTF-8'): int
265
    {
266
        if (!is_string($value)) {
267
            $value = (string) $value;
268
        }
269
270
        $length = mb_strlen($value, $encode);
271
272
        return $length !== false ? $length : -1;
273
    }
274
275
276
    /**
277
     * Add padding to string
278
     * @param string|int $value
279
     * @param int $length
280
     * @param string $padStr
281
     * @param int $type
282
     * @return string
283
     */
284
    public static function pad(
285
        $value,
286
        int $length,
287
        string $padStr,
288
        int $type = STR_PAD_BOTH
289
    ): string {
290
        if (!is_string($value)) {
291
            $value = (string) $value;
292
        }
293
294
        return $length > 0
295
                ? str_pad($value, $length, $padStr, $type)
296
                : $value;
297
    }
298
299
    /**
300
     * Add padding to string to left
301
     * @param string|int $value
302
     * @param int $length
303
     * @param string $padStr
304
     * @return string
305
     */
306
    public static function padLeft(
307
        $value,
308
        int $length,
309
        string $padStr
310
    ): string {
311
        return self::pad($value, $length, $padStr, STR_PAD_LEFT);
312
    }
313
314
    /**
315
     * Add padding to string to right
316
     * @param string|int $value
317
     * @param int $length
318
     * @param string $padStr
319
     * @return string
320
     */
321
    public static function padRight(
322
        $value,
323
        int $length,
324
        string $padStr
325
    ): string {
326
        return self::pad($value, $length, $padStr, STR_PAD_RIGHT);
327
    }
328
329
    /**
330
     * Repeat the given string $length times
331
     * @param string|int $value
332
     * @param int $length
333
     * @return string
334
     */
335
    public static function repeat($value, int $length = 1): string
336
    {
337
        if (!is_string($value)) {
338
            $value = (string) $value;
339
        }
340
341
        return str_repeat($value, $length);
342
    }
343
344
    /**
345
     * Limit the length of given string
346
     * @param string $value
347
     * @param int $length
348
     * @param string $end
349
     * @return string
350
     */
351
    public static function limit(string $value, int $length = 100, string $end = '...'): string
352
    {
353
        if (mb_strwidth($value, 'UTF-8') <= $length) {
354
            return $value;
355
        }
356
357
        return rtrim(mb_strimwidth($value, 0, $length, '', 'UTF-8')) . $end;
358
    }
359
360
    /**
361
     * Limit the number of words in a string.
362
     * @param string $value
363
     * @param int $length
364
     * @param string $end
365
     * @return string
366
     */
367
    public static function words(string $value, int $length = 100, string $end = '...'): string
368
    {
369
        $matches = [];
370
        preg_match('/^\s*+(?:\S++\s*+){1,' . $length . '}/u', $value, $matches);
371
372
        if (!isset($matches[0]) || strlen($value) === strlen($matches[0])) {
373
            return $value;
374
        }
375
376
        return rtrim($matches[0]) . $end;
377
    }
378
379
    /**
380
     * Replace the first match of the given string
381
     * @param string $search
382
     * @param string $replace
383
     * @param string $value
384
     * @return string
385
     */
386
    public static function replaceFirst(string $search, string $replace, string $value): string
387
    {
388
        $pos = strpos($value, $search);
389
        if ($pos !== false) {
390
            return substr_replace($value, $replace, $pos, strlen($search));
0 ignored issues
show
Bug Best Practice introduced by
The expression return substr_replace($v... $pos, strlen($search)) could return the type array which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
391
        }
392
393
        return $value;
394
    }
395
396
    /**
397
     * Replace the last match of the given string
398
     * @param string $search
399
     * @param string $replace
400
     * @param string $value
401
     * @return string
402
     */
403
    public static function replaceLast(string $search, string $replace, string $value): string
404
    {
405
        $pos = strrpos($value, $search);
406
407
        if ($pos !== false) {
408
            return substr_replace($value, $replace, $pos, strlen($search));
0 ignored issues
show
Bug Best Practice introduced by
The expression return substr_replace($v... $pos, strlen($search)) could return the type array which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
409
        }
410
411
        return $value;
412
    }
413
414
    /**
415
     * Put the string to title format
416
     * @param string $value
417
     * @return string
418
     */
419
    public static function title(string $value): string
420
    {
421
        return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');
422
    }
423
424
    /**
425
     * Generate a friendly "slug" from a given string.
426
     * @param string $value
427
     * @param string $separator
428
     * @return string
429
     */
430
    public static function slug(string $value, string $separator = '-'): string
431
    {
432
        $title = self::toAscii($value);
433
434
        // Convert all dashes/underscores into separator
435
        $flip = $separator === '-' ? '_' : '-';
436
437
        $utf8 = (string) preg_replace('![' . preg_quote($flip) . ']+!u', $separator, $title);
438
439
        // Remove all characters that are not the separator, letters, numbers,
440
        // or whitespace.
441
        $alphaNum = (string) preg_replace(
442
            '![^' . preg_quote($separator) . '\pL\pN\s]+!u',
443
            '',
444
            mb_strtolower($utf8)
445
        );
446
447
        // Replace all separator characters and whitespace by a single separator
448
        $removeWhitespace = (string) preg_replace(
449
            '![' . preg_quote($separator) . '\s]+!u',
450
            $separator,
451
            $alphaNum
452
        );
453
454
        return trim($removeWhitespace, $separator);
455
    }
456
457
    /**
458
     * Convert a string to snake case.
459
     * @param string $value
460
     * @param string $separator
461
     * @return string
462
     */
463
    public static function snake(string $value, string $separator = '_'): string
464
    {
465
        $key = $value . $separator;
466
        if (isset(self::$snakeCache[$key])) {
467
            return self::$snakeCache[$key];
468
        }
469
470
        if (!ctype_lower($value)) {
471
            $replace = (string) preg_replace('/\s+/', '', $value);
472
473
            $value = strtolower((string) preg_replace(
474
                '/(.)(?=[A-Z])/',
475
                '$1' . $separator,
476
                $replace
477
            ));
478
        }
479
480
        return self::$snakeCache[$key] = $value;
481
    }
482
483
    /**
484
     * Convert a value to studly caps case.
485
     * @param string $value
486
     * @return string
487
     */
488
    public static function studly(string $value): string
489
    {
490
        $key = $value;
491
        if (isset(self::$studlyCache[$key])) {
492
            return self::$studlyCache[$key];
493
        }
494
495
        $val = ucwords(str_replace(['-', '_'], ' ', $value));
496
497
        return self::$studlyCache[$key] = str_replace(' ', '', $val);
498
    }
499
500
    /**
501
     * Returns the portion of string specified by the start and
502
     * length parameters.
503
     *
504
     * @param string $value
505
     * @param int $start
506
     * @param int|null $length
507
     * @return string
508
     */
509
    public static function substr(string $value, int $start = 0, ?int $length = null): string
510
    {
511
        return mb_substr($value, $start, $length, 'UTF-8');
512
    }
513
514
    /**
515
     * Make a string's first character to upper case.
516
     * @param string $value
517
     * @return string
518
     */
519
    public static function ucfirst(string $value): string
520
    {
521
        return static::upper(
522
            static::substr($value, 0, 1)
523
        ) . static::substr($value, 1);
524
    }
525
526
    /**
527
     * Split the string by length part
528
     * @param string $value
529
     * @param int $length
530
     * @return array<int, string>
531
     */
532
    public static function split(string $value, int $length = 1): array
533
    {
534
        if ($length < 1) {
535
            return [];
536
        }
537
538
        if (self::isAscii($value)) {
539
            $res = str_split($value, $length);
540
            if ($res === false) {
541
                return [];
542
            }
543
544
            return $res;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $res could return the type true which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
545
        }
546
547
        if (mb_strlen($value) <= $length) {
548
            return [$value];
549
        }
550
        $matches = [];
551
        preg_match_all(
552
            '/.{' . $length . '}|[^\x00]{1,' . $length . '}$/us',
553
            $value,
554
            $matches
555
        );
556
557
        return $matches[0];
558
    }
559
560
    /**
561
     * Check whether the given string contains only ASCII chars
562
     * @param string $value
563
     * @return bool
564
     */
565
    public static function isAscii(string $value): bool
566
    {
567
        return (bool)!preg_match('/[^\x00-\x7F]/S', $value);
568
    }
569
570
    /**
571
     * Put string to lower case
572
     * @param string $value
573
     * @return string
574
     */
575
    public static function lower(string $value): string
576
    {
577
        return mb_strtolower($value, 'UTF-8');
578
    }
579
580
    /**
581
     * Put string to upper case
582
     * @param string $value
583
     * @return string
584
     */
585
    public static function upper(string $value): string
586
    {
587
        return mb_strtoupper($value, 'UTF-8');
588
    }
589
590
    /**
591
     * Return the unique ID
592
     * @param int $length
593
     *
594
     * @return string
595
     */
596
    public static function uniqId(int $length = 13): string
597
    {
598
        $bytes = random_bytes((int) ceil($length / 2));
599
600
        return (string)substr(bin2hex($bytes), 0, $length);
601
    }
602
603
    /**
604
     * Generate random string value
605
     * @param int $length
606
     * @return string
607
     */
608
    public static function random(int $length = 16): string
609
    {
610
        $string = '';
611
        while (($len = strlen($string)) < $length) {
612
            $size = $length - $len;
613
            $bytes = random_bytes($size);
614
615
            $string .= substr(
616
                str_replace(['/', '+', '='], '', base64_encode($bytes)),
617
                0,
618
                $size
619
            );
620
        }
621
622
        return $string;
623
    }
624
625
    /**
626
     * Generates a random string of a given type and length. Possible
627
     * values for the first argument ($type) are:
628
     *  - alnum    - alpha-numeric characters (including capitals)
629
     *  - alpha    - alphabetical characters (including capitals)
630
     *  - hexdec   - hexadecimal characters, 0-9 plus a-f
631
     *  - numeric  - digit characters, 0-9
632
     *  - nozero   - digit characters, 1-9
633
     *  - distinct - clearly distinct alpha-numeric characters.
634
     * @param string $type
635
     * @param int $length
636
     * @return string
637
     */
638
    public static function randomString(string $type = 'alnum', int $length = 8): string
639
    {
640
        $utf8 = false;
641
642
        switch ($type) {
643
            case 'alnum':
644
                $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
645
                break;
646
            case 'alpha':
647
                $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
648
                break;
649
            case 'lowalnum':
650
                $pool = '0123456789abcdefghijklmnopqrstuvwxyz';
651
                break;
652
            case 'hexdec':
653
                $pool = '0123456789abcdef';
654
                break;
655
            case 'numeric':
656
                $pool = '0123456789';
657
                break;
658
            case 'nozero':
659
                $pool = '123456789';
660
                break;
661
            case 'distinct':
662
                $pool = '2345679ACDEFHJKLMNPRSTUVWXYZ';
663
                break;
664
            default:
665
                $pool = (string)$type;
666
                $utf8 = !self::isAscii($pool);
667
                break;
668
        }
669
670
        // Split the pool into an array of characters
671
        $pool = $utf8 ? self::split($pool, 1) : str_split($pool, 1);
672
        // Largest pool key
673
        $max = count($pool) - 1;
0 ignored issues
show
Bug introduced by
It seems like $pool can also be of type true; however, parameter $value of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

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

673
        $max = count(/** @scrutinizer ignore-type */ $pool) - 1;
Loading history...
674
675
        $str = '';
676
        for ($i = 0; $i < $length; $i++) {
677
            // Select a random character from the pool and add it to the string
678
            $str .= $pool[random_int(0, $max)];
679
        }
680
681
        // Make sure alnum strings contain at least one letter and one digit
682
        if ($type === 'alnum' && $length > 1) {
683
            if (ctype_alpha($str)) {
684
                // Add a random digit
685
                $str[random_int(0, $length - 1)] = chr(random_int(48, 57));
686
            } elseif (ctype_digit($str)) {
687
                // Add a random letter
688
                $str[random_int(0, $length - 1)] = chr(random_int(65, 90));
689
            }
690
        }
691
692
        return $str;
693
    }
694
695
    /**
696
     * Create a simple random token-string
697
     * @param int $length
698
     * @param string $salt
699
     * @return string
700
     */
701
    public static function randomToken(int $length = 24, string $salt = ''): string
702
    {
703
        $string = '';
704
        $chars  = '0456789abc1def2ghi3jkl';
705
        $maxVal = strlen($chars) - 1;
706
707
        for ($i = 0; $i < $length; ++$i) {
708
            $string .= $chars[random_int(0, $maxVal)];
709
        }
710
711
        return md5($string . $salt);
712
    }
713
714
    /**
715
     * Return the ASCII replacement
716
     * @return array<string, array<string>>
717
     */
718
    private static function getChars(): array
719
    {
720
        return [
721
            '0'    => ['°', '₀'],
722
            '1'    => ['¹', '₁'],
723
            '2'    => ['²', '₂'],
724
            '3'    => ['³', '₃'],
725
            '4'    => ['⁴', '₄'],
726
            '5'    => ['⁵', '₅'],
727
            '6'    => ['⁶', '₆'],
728
            '7'    => ['⁷', '₇'],
729
            '8'    => ['⁸', '₈'],
730
            '9'    => ['⁹', '₉'],
731
            'a'    => [
732
                'à',
733
                'á',
734
                'ả',
735
                'ã',
736
                'ạ',
737
                'ă',
738
                'ắ',
739
                'ằ',
740
                'ẳ',
741
                'ẵ',
742
                'ặ',
743
                'â',
744
                'ấ',
745
                'ầ',
746
                'ẩ',
747
                'ẫ',
748
                'ậ',
749
                'ā',
750
                'ą',
751
                'å',
752
                'α',
753
                'ά',
754
                'ἀ',
755
                'ἁ',
756
                'ἂ',
757
                'ἃ',
758
                'ἄ',
759
                'ἅ',
760
                'ἆ',
761
                'ἇ',
762
                'ᾀ',
763
                'ᾁ',
764
                'ᾂ',
765
                'ᾃ',
766
                'ᾄ',
767
                'ᾅ',
768
                'ᾆ',
769
                'ᾇ',
770
                'ὰ',
771
                'ά',
772
                'ᾰ',
773
                'ᾱ',
774
                'ᾲ',
775
                'ᾳ',
776
                'ᾴ',
777
                'ᾶ',
778
                'ᾷ',
779
                'а',
780
                'أ',
781
                'အ',
782
                'ာ',
783
                'ါ',
784
                'ǻ',
785
                'ǎ',
786
                'ª',
787
                'ა',
788
                'अ'
789
            ],
790
            'b'    => ['б', 'β', 'Ъ', 'Ь', 'ب', 'ဗ', 'ბ'],
791
            'c'    => ['ç', 'ć', 'č', 'ĉ', 'ċ'],
792
            'd'    => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ', 'д', 'δ', 'د', 'ض', 'ဍ', 'ဒ', 'დ'],
793
            'e'    => [
794
                'é',
795
                'è',
796
                'ẻ',
797
                'ẽ',
798
                'ẹ',
799
                'ê',
800
                'ế',
801
                'ề',
802
                'ể',
803
                'ễ',
804
                'ệ',
805
                'ë',
806
                'ē',
807
                'ę',
808
                'ě',
809
                'ĕ',
810
                'ė',
811
                'ε',
812
                'έ',
813
                'ἐ',
814
                'ἑ',
815
                'ἒ',
816
                'ἓ',
817
                'ἔ',
818
                'ἕ',
819
                'ὲ',
820
                'έ',
821
                'е',
822
                'ё',
823
                'э',
824
                'є',
825
                'ə',
826
                'ဧ',
827
                'ေ',
828
                'ဲ',
829
                'ე',
830
                'ए'
831
            ],
832
            'f'    => ['ф', 'φ', 'ف', 'ƒ', 'ფ'],
833
            'g'    => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ج', 'ဂ', 'გ'],
834
            'h'    => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ'],
835
            'i'    => [
836
                'í',
837
                'ì',
838
                'ỉ',
839
                'ĩ',
840
                'ị',
841
                'î',
842
                'ï',
843
                'ī',
844
                'ĭ',
845
                'į',
846
                'ı',
847
                'ι',
848
                'ί',
849
                'ϊ',
850
                'ΐ',
851
                'ἰ',
852
                'ἱ',
853
                'ἲ',
854
                'ἳ',
855
                'ἴ',
856
                'ἵ',
857
                'ἶ',
858
                'ἷ',
859
                'ὶ',
860
                'ί',
861
                'ῐ',
862
                'ῑ',
863
                'ῒ',
864
                'ΐ',
865
                'ῖ',
866
                'ῗ',
867
                'і',
868
                'ї',
869
                'и',
870
                'ဣ',
871
                'ိ',
872
                'ီ',
873
                'ည်',
874
                'ǐ',
875
                'ი',
876
                'इ'
877
            ],
878
            'j'    => ['ĵ', 'ј', 'Ј', 'ჯ'],
879
            'k'    => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك', 'က', 'კ', 'ქ'],
880
            'l'    => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ'],
881
            'm'    => ['м', 'μ', 'م', 'မ', 'მ'],
882
            'n'    => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن', 'န', 'ნ'],
883
            'o'    => [
884
                'ó',
885
                'ò',
886
                'ỏ',
887
                'õ',
888
                'ọ',
889
                'ô',
890
                'ố',
891
                'ồ',
892
                'ổ',
893
                'ỗ',
894
                'ộ',
895
                'ơ',
896
                'ớ',
897
                'ờ',
898
                'ở',
899
                'ỡ',
900
                'ợ',
901
                'ø',
902
                'ō',
903
                'ő',
904
                'ŏ',
905
                'ο',
906
                'ὀ',
907
                'ὁ',
908
                'ὂ',
909
                'ὃ',
910
                'ὄ',
911
                'ὅ',
912
                'ὸ',
913
                'ό',
914
                'о',
915
                'و',
916
                'θ',
917
                'ို',
918
                'ǒ',
919
                'ǿ',
920
                'º',
921
                'ო',
922
                'ओ'
923
            ],
924
            'p'    => ['п', 'π', 'ပ', 'პ'],
925
            'q'    => ['ყ'],
926
            'r'    => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ'],
927
            's'    => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص', 'စ', 'ſ', 'ს'],
928
            't'    => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط', 'ဋ', 'တ', 'ŧ', 'თ', 'ტ'],
929
            'u'    => [
930
                'ú',
931
                'ù',
932
                'ủ',
933
                'ũ',
934
                'ụ',
935
                'ư',
936
                'ứ',
937
                'ừ',
938
                'ử',
939
                'ữ',
940
                'ự',
941
                'û',
942
                'ū',
943
                'ů',
944
                'ű',
945
                'ŭ',
946
                'ų',
947
                'µ',
948
                'у',
949
                'ဉ',
950
                'ု',
951
                'ူ',
952
                'ǔ',
953
                'ǖ',
954
                'ǘ',
955
                'ǚ',
956
                'ǜ',
957
                'უ',
958
                'उ'
959
            ],
960
            'v'    => ['в', 'ვ', 'ϐ'],
961
            'w'    => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ'],
962
            'x'    => ['χ', 'ξ'],
963
            'y'    => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ', 'ϋ', 'ύ', 'ΰ', 'ي', 'ယ'],
964
            'z'    => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ'],
965
            'aa'   => ['ع', 'आ'],
966
            'ae'   => ['ä', 'æ', 'ǽ'],
967
            'ai'   => ['ऐ'],
968
            'at'   => ['@'],
969
            'ch'   => ['ч', 'ჩ', 'ჭ'],
970
            'dj'   => ['ђ', 'đ'],
971
            'dz'   => ['џ', 'ძ'],
972
            'ei'   => ['ऍ'],
973
            'gh'   => ['غ', 'ღ'],
974
            'ii'   => ['ई'],
975
            'ij'   => ['ij'],
976
            'kh'   => ['х', 'خ', 'ხ'],
977
            'lj'   => ['љ'],
978
            'nj'   => ['њ'],
979
            'oe'   => ['ö', 'œ'],
980
            'oi'   => ['ऑ'],
981
            'oii'  => ['ऒ'],
982
            'ps'   => ['ψ'],
983
            'sh'   => ['ш', 'შ'],
984
            'shch' => ['щ'],
985
            'ss'   => ['ß'],
986
            'sx'   => ['ŝ'],
987
            'th'   => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'],
988
            'ts'   => ['ц', 'ც', 'წ'],
989
            'ue'   => ['ü'],
990
            'uu'   => ['ऊ'],
991
            'ya'   => ['я'],
992
            'yu'   => ['ю'],
993
            'zh'   => ['ж', 'ჟ'],
994
            '(c)'  => ['©'],
995
            'A'    => [
996
                'Á',
997
                'À',
998
                'Ả',
999
                'Ã',
1000
                'Ạ',
1001
                'Ă',
1002
                'Ắ',
1003
                'Ằ',
1004
                'Ẳ',
1005
                'Ẵ',
1006
                'Ặ',
1007
                'Â',
1008
                'Ấ',
1009
                'Ầ',
1010
                'Ẩ',
1011
                'Ẫ',
1012
                'Ậ',
1013
                'Å',
1014
                'Ā',
1015
                'Ą',
1016
                'Α',
1017
                'Ά',
1018
                'Ἀ',
1019
                'Ἁ',
1020
                'Ἂ',
1021
                'Ἃ',
1022
                'Ἄ',
1023
                'Ἅ',
1024
                'Ἆ',
1025
                'Ἇ',
1026
                'ᾈ',
1027
                'ᾉ',
1028
                'ᾊ',
1029
                'ᾋ',
1030
                'ᾌ',
1031
                'ᾍ',
1032
                'ᾎ',
1033
                'ᾏ',
1034
                'Ᾰ',
1035
                'Ᾱ',
1036
                'Ὰ',
1037
                'Ά',
1038
                'ᾼ',
1039
                'А',
1040
                'Ǻ',
1041
                'Ǎ'
1042
            ],
1043
            'B'    => ['Б', 'Β', 'ब'],
1044
            'C'    => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ'],
1045
            'D'    => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ'],
1046
            'E'    => [
1047
                'É',
1048
                'È',
1049
                'Ẻ',
1050
                'Ẽ',
1051
                'Ẹ',
1052
                'Ê',
1053
                'Ế',
1054
                'Ề',
1055
                'Ể',
1056
                'Ễ',
1057
                'Ệ',
1058
                'Ë',
1059
                'Ē',
1060
                'Ę',
1061
                'Ě',
1062
                'Ĕ',
1063
                'Ė',
1064
                'Ε',
1065
                'Έ',
1066
                'Ἐ',
1067
                'Ἑ',
1068
                'Ἒ',
1069
                'Ἓ',
1070
                'Ἔ',
1071
                'Ἕ',
1072
                'Έ',
1073
                'Ὲ',
1074
                'Е',
1075
                'Ё',
1076
                'Э',
1077
                'Є',
1078
                'Ə'
1079
            ],
1080
            'F'    => ['Ф', 'Φ'],
1081
            'G'    => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ'],
1082
            'H'    => ['Η', 'Ή', 'Ħ'],
1083
            'I'    => [
1084
                'Í',
1085
                'Ì',
1086
                'Ỉ',
1087
                'Ĩ',
1088
                'Ị',
1089
                'Î',
1090
                'Ï',
1091
                'Ī',
1092
                'Ĭ',
1093
                'Į',
1094
                'İ',
1095
                'Ι',
1096
                'Ί',
1097
                'Ϊ',
1098
                'Ἰ',
1099
                'Ἱ',
1100
                'Ἳ',
1101
                'Ἴ',
1102
                'Ἵ',
1103
                'Ἶ',
1104
                'Ἷ',
1105
                'Ῐ',
1106
                'Ῑ',
1107
                'Ὶ',
1108
                'Ί',
1109
                'И',
1110
                'І',
1111
                'Ї',
1112
                'Ǐ',
1113
                'ϒ'
1114
            ],
1115
            'K'    => ['К', 'Κ'],
1116
            'L'    => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल'],
1117
            'M'    => ['М', 'Μ'],
1118
            'N'    => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν'],
1119
            'O'    => [
1120
                'Ó',
1121
                'Ò',
1122
                'Ỏ',
1123
                'Õ',
1124
                'Ọ',
1125
                'Ô',
1126
                'Ố',
1127
                'Ồ',
1128
                'Ổ',
1129
                'Ỗ',
1130
                'Ộ',
1131
                'Ơ',
1132
                'Ớ',
1133
                'Ờ',
1134
                'Ở',
1135
                'Ỡ',
1136
                'Ợ',
1137
                'Ø',
1138
                'Ō',
1139
                'Ő',
1140
                'Ŏ',
1141
                'Ο',
1142
                'Ό',
1143
                'Ὀ',
1144
                'Ὁ',
1145
                'Ὂ',
1146
                'Ὃ',
1147
                'Ὄ',
1148
                'Ὅ',
1149
                'Ὸ',
1150
                'Ό',
1151
                'О',
1152
                'Θ',
1153
                'Ө',
1154
                'Ǒ',
1155
                'Ǿ'
1156
            ],
1157
            'P'    => ['П', 'Π'],
1158
            'R'    => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ'],
1159
            'S'    => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ'],
1160
            'T'    => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ'],
1161
            'U'    => [
1162
                'Ú',
1163
                'Ù',
1164
                'Ủ',
1165
                'Ũ',
1166
                'Ụ',
1167
                'Ư',
1168
                'Ứ',
1169
                'Ừ',
1170
                'Ử',
1171
                'Ữ',
1172
                'Ự',
1173
                'Û',
1174
                'Ū',
1175
                'Ů',
1176
                'Ű',
1177
                'Ŭ',
1178
                'Ų',
1179
                'У',
1180
                'Ǔ',
1181
                'Ǖ',
1182
                'Ǘ',
1183
                'Ǚ',
1184
                'Ǜ'
1185
            ],
1186
            'V'    => ['В'],
1187
            'W'    => ['Ω', 'Ώ', 'Ŵ'],
1188
            'X'    => ['Χ', 'Ξ'],
1189
            'Y'    => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ', 'Ы', 'Й', 'Υ', 'Ϋ', 'Ŷ'],
1190
            'Z'    => ['Ź', 'Ž', 'Ż', 'З', 'Ζ'],
1191
            'AE'   => ['Ä', 'Æ', 'Ǽ'],
1192
            'CH'   => ['Ч'],
1193
            'DJ'   => ['Ђ'],
1194
            'DZ'   => ['Џ'],
1195
            'GX'   => ['Ĝ'],
1196
            'HX'   => ['Ĥ'],
1197
            'IJ'   => ['IJ'],
1198
            'JX'   => ['Ĵ'],
1199
            'KH'   => ['Х'],
1200
            'LJ'   => ['Љ'],
1201
            'NJ'   => ['Њ'],
1202
            'OE'   => ['Ö', 'Œ'],
1203
            'PS'   => ['Ψ'],
1204
            'SH'   => ['Ш'],
1205
            'SHCH' => ['Щ'],
1206
            'SS'   => ['ẞ'],
1207
            'TH'   => ['Þ'],
1208
            'TS'   => ['Ц'],
1209
            'UE'   => ['Ü'],
1210
            'YA'   => ['Я'],
1211
            'YU'   => ['Ю'],
1212
            'ZH'   => ['Ж'],
1213
            ' '    => [
1214
                "\xC2\xA0",
1215
                "\xE2\x80\x80",
1216
                "\xE2\x80\x81",
1217
                "\xE2\x80\x82",
1218
                "\xE2\x80\x83",
1219
                "\xE2\x80\x84",
1220
                "\xE2\x80\x85",
1221
                "\xE2\x80\x86",
1222
                "\xE2\x80\x87",
1223
                "\xE2\x80\x88",
1224
                "\xE2\x80\x89",
1225
                "\xE2\x80\x8A",
1226
                "\xE2\x80\xAF",
1227
                "\xE2\x81\x9F",
1228
                "\xE3\x80\x80"
1229
            ],
1230
        ];
1231
    }
1232
}
1233