GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Strings::fromVariable()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
c 1
b 0
f 0
nc 3
nop 3
dl 0
loc 7
rs 10
ccs 3
cts 3
cp 1
crap 3
1
<?php
2
/**
3
 * Class Strings
4
 *
5
 * @link https://www.icy2003.com/
6
 * @author icy2003 <[email protected]>
7
 * @copyright Copyright (c) 2017, icy2003
8
 */
9
10
namespace icy2003\php\ihelpers;
11
12
use Exception;
13
use icy2003\php\C;
14
use icy2003\php\I;
15
16
/**
17
 * 字符串类
18
 *
19
 * @test icy2003\php_tests\ihelpers\StringsTest
20
 */
21
class Strings
22
{
23
24
    /**
25
     * 返回字符串的字节长
26
     *
27
     * - 一个中文等于 3 字节
28
     *
29
     * @param string $string
30
     *
31
     * @return integer
32
     *
33
     * @tested
34
     */
35 1
    public static function byteLength($string)
36
    {
37 1
        return mb_strlen($string, '8bit');
38
    }
39
    /**
40
     * 返回字符个数
41
     *
42
     * - 一个中文就是 1 个
43
     *
44
     * @param string $string
45
     *
46
     * @return integer
47
     *
48
     * @tested
49
     */
50 9
    public static function length($string)
51
    {
52 9
        return mb_strlen($string, 'UTF-8');
53
    }
54
55
    /**
56
     * 随机数种子(数字)
57
     */
58
    const STRINGS_RANDOM_NUMBER = '0123456789';
59
60
    /**
61
     * 随机数种子(小写字母)
62
     */
63
    const STRINGS_RANDOM_LOWERCASE = 'abcdefghijklmnopqrstuvwxyz';
64
65
    /**
66
     * 随机数种子(大写字母)
67
     */
68
    const STRINGS_RANDOM_UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
69
70
    /**
71
     * 生成随机字符串
72
     *
73
     * @param integer $length 随机字符串的长度,默认 32
74
     * @param string $chars 字符列表,默认为0-9和大小写字母
75
     *
76
     * @return string
77
     *
78
     * @test
79
     */
80 1
    public static function random($length = 32, $chars = self::STRINGS_RANDOM_NUMBER . self::STRINGS_RANDOM_LOWERCASE . self::STRINGS_RANDOM_UPPERCASE)
81
    {
82 1
        $str = '';
83 1
        for ($i = 0; $i < $length; ++$i) {
84 1
            $str .= mb_substr($chars, mt_rand(0, self::length($chars) - 1), 1);
85
        }
86
87 1
        return $str;
88
    }
89
90
    /**
91
     * 小驼峰转化成下划线(如需要大写下划线,用 strtoupper 转化即可)
92
     *
93
     * @param string $string
94
     *
95
     * @return string
96
     *
97
     * @tested
98
     */
99 1
    public static function toUnderline($string)
100
    {
101 1
        return strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $string));
102
    }
103
104
    /**
105
     * 下划线转化为小驼峰(如需要大驼峰,用 ucfirst 转化即可)
106
     *
107
     * @param string $string
108
     *
109
     * @return string
110
     *
111
     * @tested
112
     */
113 3
    public static function toCamel($string)
114
    {
115
        return lcfirst(preg_replace_callback('/_+([a-z0-9_\x7f-\xff])/', function ($matches) {
116 1
            return ucfirst($matches[1]);
117 3
        }, strtolower($string)));
118
    }
119
120
    /**
121
     * 格式化成标题格式(每个单词首字母大写)
122
     *
123
     * @param string $string
124
     *
125
     * @return string
126
     *
127
     * @tested
128
     */
129 1
    public static function toTitle($string)
130
    {
131 1
        return mb_convert_case($string, MB_CASE_TITLE, 'UTF-8');
132
    }
133
134
    /**
135
     * 检查字符串是否以某字符串开头
136
     *
137
     * @param string $string
138
     * @param string $search 待搜索子字符串
139
     *
140
     * @return boolean
141
     *
142
     * @tested
143
     */
144 10
    public static function isStartsWith($string, $search)
145
    {
146 10
        return (string) $search !== "" && mb_strpos($string, $search) === 0;
147
    }
148
149
    /**
150
     * 检查字符串是否以某字符串结尾
151
     *
152
     * @param string $string
153
     * @param string $search 待搜索子字符串
154
     *
155
     * @return boolean
156
     *
157
     * @tested
158
     */
159 3
    public static function isEndsWith($string, $search)
160
    {
161 3
        return (string) $search !== "" && mb_substr($string, -static::length($search)) === $search;
162
    }
163
164
    /**
165
     * 检查字符串中是否包含某字符串
166
     *
167
     * @param string $string
168
     * @param string $search 待搜索子字符串
169
     * @param integer $pos 如果找到子串,则引用出子串的起始位置
170
     *
171
     * @return boolean
172
     *
173
     * @tested
174
     */
175 6
    public static function isContains($string, $search, &$pos = null)
176
    {
177 6
        return (string) $search !== "" && ($pos = mb_strpos($string, $search)) !== false;
178
    }
179
180
    /**
181
     * 在字符串里找子串的前部分
182
     *
183
     * @param string $string
184
     * @param string $search
185
     * @param integer $pos 如果找到子串,则引用出子串的起始位置
186
     *
187
     * @return string
188
     *
189
     * @tested
190
     */
191 1
    public static function partBefore($string, $search, &$pos = null)
192
    {
193 1
        if (self::isContains($string, $search, $pos)) {
194 1
            return mb_substr($string, 0, $pos);
195
        }
196 1
        return '';
197
    }
198
199
    /**
200
     * 在字符串里找子串的后部分
201
     *
202
     * @param string $string
203
     * @param string $search
204
     * @param integer $pos 如果找到子串,则引用出子串的起始位置
205
     *
206
     * @return string
207
     *
208
     * @tested
209
     */
210 1
    public static function partAfter($string, $search, &$pos = null)
211
    {
212 1
        if (self::isContains($string, $search, $pos)) {
213 1
            return mb_substr($string, $pos + self::length($search), self::length($string) - 1);
214
        }
215 1
        return '';
216
    }
217
218
    /**
219
     * 在字符串中找子串的中间部分,需指定前半部分和后半部分
220
     *
221
     * @param string $string
222
     * @param string $beforeString
223
     * @param string $afterString
224
     *
225
     * @return string
226
     */
227 1
    public static function partBetween($string, $beforeString, $afterString)
228
    {
229 1
        if (self::isContains($string, $beforeString, $p1) && self::isContains($string, $afterString, $p2)) {
230
            $len1 = $p1 + self::length($beforeString);
231
            return mb_substr($string, $len1, $p2 - $len1);
232
        }
233
        return '';
234
    }
235
236
    /**
237
     * 反转字符串,支持中文
238
     *
239
     * @param string $string
240
     *
241 4
     * @return string
242
     *
243 4
     * @tested
244
     */
245
    public static function reverse($string)
246
    {
247
        return implode('', array_reverse(self::split($string)));
248
    }
249
250
    /**
251
     * 把字符串打散为数组
252
     *
253
     * @param string $string
254
     *
255
     * @return array
256
     *
257 4
     * @tested
258
     */
259 4
    public static function split($string)
260 4
    {
261
        return (array) preg_split('/(?<!^)(?!$)/u', $string);
262 4
    }
263 4
264 1
    /**
265
     * 拆分成数组
266 4
     *
267
     * @param array|string $mixed 数组或者字符串
268
     * @param string $delimiter 分隔符,默认英文逗号(,)
269
     * @param boolean $combine 是否合并相同元素,默认 false,即不合并
270
     *
271
     * @return array
272
     *
273
     * @tested
274
     */
275
    public static function toArray($mixed, $delimiter = ',', $combine = false)
276
    {
277
        if (is_array($mixed)) {
278
            $mixed = implode($delimiter, $mixed);
279
        }
280 4
        $array = explode($delimiter, $mixed);
281
        if (true === $combine) {
282 4
            $array = Arrays::toPart($array);
283
        }
284
        return $array;
285
    }
286
287
    /**
288
     * 返回字符串的子串
289
     *
290
     * @param string $string
291
     * @param integer $start 起始位置
292
     * @param integer|null $length 子串长度,默认为 null,即返回剩下的部分
293
     *
294
     * @return string
295
     *
296 1
     * @tested
297
     */
298 1
    public static function sub($string, $start, $length = null)
299
    {
300
        return mb_substr($string, $start, $length);
301
    }
302
303
    /**
304
     * 字符串转数字
305
     *
306
     * - 正则为 `/^\d\.*\d*[e|E]/` 的字符串会……,这是 PHP 特性!如果你不喜欢 PHP,右上角
307
     *
308
     * @param string $string
309
     *
310 1
     * @return double
311
     *
312 1
     * @tested
313 1
     */
314 1
    public static function toNumber($string)
315 1
    {
316
        return (double) $string;
317 1
    }
318
319
    /**
320
     * 用回调将分隔符拆分出来的字符串执行后,用分隔符合并回去
321
     *
322
     * @param callback $callback 回调
323
     * @param string $string
324
     * @param string $delimiter 分隔符,默认英文逗号(,)
325
     *
326
     * @return string
327
     */
328
    public static function map($callback, $string, $delimiter = ',')
329 1
    {
330
        $arr = [];
331 1
        $parts = explode($delimiter, $string);
332 1
        foreach ($parts as $part) {
333
            $arr[] = I::call($callback, [$part]);
334
        }
335
        return implode($delimiter, $arr);
336
    }
337
338
    /**
339
     * 重复一个字符若干次
340
     *
341
     * @param string $char
342
     * @param integer $num
343 1
     * @param integer $maxLength 最大重复次数,默认不限制
344
     *
345 1
     * @return string
346
     */
347 1
    public static function repeat($char, $num, $maxLength = null)
348 1
    {
349
        $length = null === $maxLength ? $num : min($maxLength, $num);
350
        return str_repeat($char, $length);
351
    }
352
353
    /**
354
     * 生成密码 hash
355
     *
356
     * @param string $password 原始密码
357
     * @param integer $cost
358
     *
359
     * @return string
360
     */
361
    public static function generatePasswordHash($password, $cost = null)
362
    {
363
        null === $cost && $cost = 13;
364
        // PHP 5 >= 5.5.0, PHP 7
365
        if (function_exists('password_hash')) {
366 1
            return password_hash($password, PASSWORD_DEFAULT, ['cost' => $cost]);
367
        }
368 1
        C::assertNotTrue($cost < 4 || $cost > 31, 'cost 必须大于等于 4,小于等于 31');
369
        $salt = sprintf('$2y$%02d$', $cost);
370
        $salt .= str_replace('+', '.', substr(base64_encode(self::random(20)), 0, 22));
371 1
        $hash = crypt($password, $salt);
372 1
        C::assertNotTrue(!is_string($hash) || strlen($hash) !== 60, '未知错误');
373 1
        return $hash;
374 1
    }
375
376
    /**
377
     * 验证密码
378 1
     *
379 1
     * @param string $password 原始密码
380
     * @param string $hash HASH 后的密码,需配合 Strings::generatePasswordHash
381
     *
382
     * @return boolean
383
     */
384
    public static function validatePassword($password, $hash)
385
    {
386
        if (!is_string($password) || $password === '') {
0 ignored issues
show
introduced by
The condition is_string($password) is always true.
Loading history...
387
            return false;
388
        }
389
        $matches = [];
390
        if (!preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hash, $matches)
391
            || $matches[1] < 4
392
            || $matches[1] > 30) {
393
            return false;
394
        }
395
        // PHP 5 >= 5.5.0, PHP 7
396
        if (function_exists('password_verify')) {
397
            return password_verify($password, $hash);
398
        }
399
400
        $test = crypt($password, $hash);
401
        $n = strlen($test);
402
        if ($n !== 60) {
403
            return false;
404
        }
405
        // PHP 5 >= 5.6.0, PHP 7
406
        if (function_exists('hash_equals')) {
407
            return hash_equals($test, $hash);
408
        }
409
410
        $test .= '\0';
411
        $hash .= '\0';
412
        $expectedLength = self::byteLength($test);
413
        $actualLength = self::byteLength($hash);
414
        $diff = $expectedLength - $actualLength;
415 1
        for ($i = 0; $i < $actualLength; $i++) {
416
            $diff |= (ord($hash[$i]) ^ ord($test[$i % $expectedLength]));
417 1
        }
418 1
419
        return $diff === 0;
420 1
    }
421
422
    /**
423
     * 字符串转成变量
424
     *
425
     * - 变量是被如:{{}}括起来的字符串
426
     * - 例如:{{var}}
427
     *
428
     * @param string $name
429
     * @param array $boundary 边界符,默认 ['{{', '}}']
430
     *
431 2
     * @return string
432
     */
433 2
    public static function toVariable($name, $boundary = ['{{', '}}'])
434
    {
435
        if (is_string($boundary)) {
0 ignored issues
show
introduced by
The condition is_string($boundary) is always false.
Loading history...
436
            $boundary = [$boundary, $boundary];
437
        }
438
        return self::isContains($name, $boundary[0]) ? $name : $boundary[0] . $name . $boundary[1];
439
    }
440
441
    /**
442
     * 判断一个字符串是否是变量
443
     *
444
     * @param string $name
445 1
     * @param array $boundary 边界符,默认 ['{{', '}}']
446
     *
447 1
     * @return boolean
448 1
     */
449 1
    public static function isVariable($name, $boundary = ['{{', '}}'])
450
    {
451 1
        return self::isStartsWith($name, $boundary[0]) && self::isEndsWith($name, $boundary[1]);
452
    }
453
454
    /**
455
     * 计算包含变量的字符串
456
     *
457
     * @param string $text
458
     * @param array $array 键值对形式:[{{键}} => 值]。如果键不是变量,则不会替换进 $text
459
     * @param array $boundary 边界符,默认 ['{{', '}}']
460
     *
461
     * @return string
462
     */
463
    public static function fromVariable($text, $array, $boundary = ['{{', '}}'])
464
    {
465
        $data = [];
466 1
        foreach ($array as $name => $value) {
467
            self::isVariable($name, $boundary) && $data[$name] = $value;
468 1
        }
469 1
        return str_replace(array_keys($data), array_values($data), $text);
470
    }
471 1
472 1
    /**
473 1
     * 判断两个字符串像不像
474
     *
475
     * - 图形验证码里经常有人把 o 看成 0,所以……
476 1
     * - 例如:hello 和 hell0 看起来是像的 (-w-)o~
477 1
     *
478 1
     * @param string $string1 第一个字符串
479 1
     * @param string $string2 第二个字符串
480 1
     * @param array $array 看起来像的字符的列表,默认 ['0o', 'yv', 'ij', '1l']
481 1
     *
482 1
     * @return boolean
483
     */
484 1
    public static function looksLike($string1, $string2, $array = ['0oO', 'yv', 'ij', '1lI'])
485 1
    {
486 1
        if (self::length($string1) !== self::length($string2)) {
487 1
            return false;
488
        }
489
        $array1 = self::split($string1);
490 1
        $array2 = self::split($string2);
491 1
        if (empty($array1)) {
492
            return true;
493
        }
494 1
        $isEqual = false;
495
        foreach ($array1 as $index => $char1) {
496
            $char1 = strtolower($char1);
497
            $char2 = strtolower($array2[$index]);
498
            $isEqual = false;
499
            if ($char1 == $char2) {
500
                $isEqual = true;
501
            }
502
            foreach ($array as $row) {
503
                if (self::isContains($row, $char1) && self::isContains($row, $char2)) {
504
                    $isEqual = true;
505
                    break;
506
                }
507
            }
508
            if (false === $isEqual) {
509
                break;
510
            }
511
        }
512 2
        return $isEqual;
513
    }
514 2
515 2
    /**
516 2
     * 拼音编码对应表
517 2
     *
518 2
     * @var array
519 2
     */
520 2
    private static $__pinyin = ['a' => -20319, 'ai' => -20317, 'an' => -20304, 'ang' => -20295, 'ao' => -20292, 'ba' => -20283, 'bai' => -20265, 'ban' => -20257, 'bang' => -20242, 'bao' => -20230, 'bei' => -20051, 'ben' => -20036, 'beng' => -20032, 'bi' => -20026, 'bian' => -20002, 'biao' => -19990, 'bie' => -19986, 'bin' => -19982, 'bing' => -19976, 'bo' => -19805, 'bu' => -19784, 'ca' => -19775, 'cai' => -19774, 'can' => -19763, 'cang' => -19756, 'cao' => -19751, 'ce' => -19746, 'ceng' => -19741, 'cha' => -19739, 'chai' => -19728, 'chan' => -19725, 'chang' => -19715, 'chao' => -19540, 'che' => -19531, 'chen' => -19525, 'cheng' => -19515, 'chi' => -19500, 'chong' => -19484, 'chou' => -19479, 'chu' => -19467, 'chuai' => -19289, 'chuan' => -19288, 'chuang' => -19281, 'chui' => -19275, 'chun' => -19270, 'chuo' => -19263, 'ci' => -19261, 'cong' => -19249, 'cou' => -19243, 'cu' => -19242, 'cuan' => -19238, 'cui' => -19235, 'cun' => -19227, 'cuo' => -19224, 'da' => -19218, 'dai' => -19212, 'dan' => -19038, 'dang' => -19023, 'dao' => -19018, 'de' => -19006, 'deng' => -19003, 'di' => -18996, 'dian' => -18977, 'diao' => -18961, 'die' => -18952, 'ding' => -18783, 'diu' => -18774, 'dong' => -18773, 'dou' => -18763, 'du' => -18756, 'duan' => -18741, 'dui' => -18735, 'dun' => -18731, 'duo' => -18722, 'e' => -18710, 'en' => -18697, 'er' => -18696, 'fa' => -18526, 'fan' => -18518, 'fang' => -18501, 'fei' => -18490, 'fen' => -18478, 'feng' => -18463, 'fo' => -18448, 'fou' => -18447, 'fu' => -18446, 'ga' => -18239, 'gai' => -18237, 'gan' => -18231, 'gang' => -18220, 'gao' => -18211, 'ge' => -18201, 'gei' => -18184, 'gen' => -18183, 'geng' => -18181, 'gong' => -18012, 'gou' => -17997, 'gu' => -17988, 'gua' => -17970, 'guai' => -17964, 'guan' => -17961, 'guang' => -17950, 'gui' => -17947, 'gun' => -17931, 'guo' => -17928, 'ha' => -17922, 'hai' => -17759, 'han' => -17752, 'hang' => -17733, 'hao' => -17730, 'he' => -17721, 'hei' => -17703, 'hen' => -17701, 'heng' => -17697, 'hong' => -17692, 'hou' => -17683, 'hu' => -17676, 'hua' => -17496, 'huai' => -17487, 'huan' => -17482, 'huang' => -17468, 'hui' => -17454, 'hun' => -17433, 'huo' => -17427, 'ji' => -17417, 'jia' => -17202, 'jian' => -17185, 'jiang' => -16983, 'jiao' => -16970, 'jie' => -16942, 'jin' => -16915, 'jing' => -16733, 'jiong' => -16708, 'jiu' => -16706, 'ju' => -16689, 'juan' => -16664, 'jue' => -16657, 'jun' => -16647, 'ka' => -16474, 'kai' => -16470, 'kan' => -16465, 'kang' => -16459, 'kao' => -16452, 'ke' => -16448, 'ken' => -16433, 'keng' => -16429, 'kong' => -16427, 'kou' => -16423, 'ku' => -16419, 'kua' => -16412, 'kuai' => -16407, 'kuan' => -16403, 'kuang' => -16401, 'kui' => -16393, 'kun' => -16220, 'kuo' => -16216, 'la' => -16212, 'lai' => -16205, 'lan' => -16202, 'lang' => -16187, 'lao' => -16180, 'le' => -16171, 'lei' => -16169, 'leng' => -16158, 'li' => -16155, 'lia' => -15959, 'lian' => -15958, 'liang' => -15944, 'liao' => -15933, 'lie' => -15920, 'lin' => -15915, 'ling' => -15903, 'liu' => -15889, 'long' => -15878, 'lou' => -15707, 'lu' => -15701, 'lv' => -15681, 'luan' => -15667, 'lue' => -15661, 'lun' => -15659, 'luo' => -15652, 'ma' => -15640, 'mai' => -15631, 'man' => -15625, 'mang' => -15454, 'mao' => -15448, 'me' => -15436, 'mei' => -15435, 'men' => -15419, 'meng' => -15416, 'mi' => -15408, 'mian' => -15394, 'miao' => -15385, 'mie' => -15377, 'min' => -15375, 'ming' => -15369, 'miu' => -15363, 'mo' => -15362, 'mou' => -15183, 'mu' => -15180, 'na' => -15165, 'nai' => -15158, 'nan' => -15153, 'nang' => -15150, 'nao' => -15149, 'ne' => -15144, 'nei' => -15143, 'nen' => -15141, 'neng' => -15140, 'ni' => -15139, 'nian' => -15128, 'niang' => -15121, 'niao' => -15119, 'nie' => -15117, 'nin' => -15110, 'ning' => -15109, 'niu' => -14941, 'nong' => -14937, 'nu' => -14933, 'nv' => -14930, 'nuan' => -14929, 'nue' => -14928, 'nuo' => -14926, 'o' => -14922, 'ou' => -14921, 'pa' => -14914, 'pai' => -14908, 'pan' => -14902, 'pang' => -14894, 'pao' => -14889, 'pei' => -14882, 'pen' => -14873, 'peng' => -14871, 'pi' => -14857, 'pian' => -14678, 'piao' => -14674, 'pie' => -14670, 'pin' => -14668, 'ping' => -14663, 'po' => -14654, 'pu' => -14645, 'qi' => -14630, 'qia' => -14594, 'qian' => -14429, 'qiang' => -14407, 'qiao' => -14399, 'qie' => -14384, 'qin' => -14379, 'qing' => -14368, 'qiong' => -14355, 'qiu' => -14353, 'qu' => -14345, 'quan' => -14170, 'que' => -14159, 'qun' => -14151, 'ran' => -14149, 'rang' => -14145, 'rao' => -14140, 're' => -14137, 'ren' => -14135, 'reng' => -14125, 'ri' => -14123, 'rong' => -14122, 'rou' => -14112, 'ru' => -14109, 'ruan' => -14099, 'rui' => -14097, 'run' => -14094, 'ruo' => -14092, 'sa' => -14090, 'sai' => -14087, 'san' => -14083, 'sang' => -13917, 'sao' => -13914, 'se' => -13910, 'sen' => -13907, 'seng' => -13906, 'sha' => -13905, 'shai' => -13896, 'shan' => -13894, 'shang' => -13878, 'shao' => -13870, 'she' => -13859, 'shen' => -13847, 'sheng' => -13831, 'shi' => -13658, 'shou' => -13611, 'shu' => -13601, 'shua' => -13406, 'shuai' => -13404, 'shuan' => -13400, 'shuang' => -13398, 'shui' => -13395, 'shun' => -13391, 'shuo' => -13387, 'si' => -13383, 'song' => -13367, 'sou' => -13359, 'su' => -13356, 'suan' => -13343, 'sui' => -13340, 'sun' => -13329, 'suo' => -13326, 'ta' => -13318, 'tai' => -13147, 'tan' => -13138, 'tang' => -13120, 'tao' => -13107, 'te' => -13096, 'teng' => -13095, 'ti' => -13091, 'tian' => -13076, 'tiao' => -13068, 'tie' => -13063, 'ting' => -13060, 'tong' => -12888, 'tou' => -12875, 'tu' => -12871, 'tuan' => -12860, 'tui' => -12858, 'tun' => -12852, 'tuo' => -12849, 'wa' => -12838, 'wai' => -12831, 'wan' => -12829, 'wang' => -12812, 'wei' => -12802, 'wen' => -12607, 'weng' => -12597, 'wo' => -12594, 'wu' => -12585, 'xi' => -12556, 'xia' => -12359, 'xian' => -12346, 'xiang' => -12320, 'xiao' => -12300, 'xie' => -12120, 'xin' => -12099, 'xing' => -12089, 'xiong' => -12074, 'xiu' => -12067, 'xu' => -12058, 'xuan' => -12039, 'xue' => -11867, 'xun' => -11861, 'ya' => -11847, 'yan' => -11831, 'yang' => -11798, 'yao' => -11781, 'ye' => -11604, 'yi' => -11589, 'yin' => -11536, 'ying' => -11358, 'yo' => -11340, 'yong' => -11339, 'you' => -11324, 'yu' => -11303, 'yuan' => -11097, 'yue' => -11077, 'yun' => -11067, 'za' => -11055, 'zai' => -11052, 'zan' => -11045, 'zang' => -11041, 'zao' => -11038, 'ze' => -11024, 'zei' => -11020, 'zen' => -11019, 'zeng' => -11018, 'zha' => -11014, 'zhai' => -10838, 'zhan' => -10832, 'zhang' => -10815, 'zhao' => -10800, 'zhe' => -10790, 'zhen' => -10780, 'zheng' => -10764, 'zhi' => -10587, 'zhong' => -10544, 'zhou' => -10533, 'zhu' => -10519, 'zhua' => -10331, 'zhuai' => -10329, 'zhuan' => -10328, 'zhuang' => -10322, 'zhui' => -10315, 'zhun' => -10309, 'zhuo' => -10307, 'zi' => -10296, 'zong' => -10281, 'zou' => -10274, 'zu' => -10270, 'zuan' => -10262, 'zui' => -10260, 'zun' => -10256, 'zuo' => -10254];
521
522 2
    /**
523 1
     * 字符串转拼音
524 2
     *
525
     * @param string $text
526
     * @param boolean $returnArray 是否拆分返回数组,默认 false
527 2
     *
528 2
     * @return array|string
529 2
     */
530 2
    public static function toPinyin($text, $returnArray = false)
531
    {
532 2
        $text = Charset::convertTo($text, 'GB2312');
533
        $result = [];
534 2
        $length = strlen($text);
535
        for ($i = 0; $i < $length; $i++) {
536
            $p = ord(substr($text, $i, 1));
537 2
            if ($p > 160) {
538 2
                $p = $p * 256 + ord(substr($text, ++$i, 1)) - 65536;
539 1
            }
540 1
            if ($p > 0 && $p < 160) {
541
                $result[] = chr($p);
542 1
            } elseif ($p < -20319 || $p > -10247) {
543
                return '';
544
            } else {
545
                $res = '';
546
                foreach (self::$__pinyin as $pin => $code) {
547
                    if ($code > $p) {
548
                        break;
549
                    }
550
                    $res = $pin;
551
                }
552
                $result[] = $res;
553
            }
554 1
        }
555
        if (true === $returnArray) {
556 1
            return $result;
557
        } elseif (false === $returnArray) {
0 ignored issues
show
introduced by
The condition false === $returnArray is always true.
Loading history...
558 1
            return implode('', $result);
559 1
        } else {
560 1
            return implode((string) $returnArray, $result);
561 1
        }
562 1
    }
563 1
564
    /**
565 1
     * 字符串转拼音首字母
566
     *
567
     * @param string $text
568
     * @param boolean $returnArray 是否拆分返回数组,默认 false
569
     *
570
     * @return array|string
571
     */
572
    public static function toPinyinFirst($text, $returnArray = false)
573
    {
574
        $array = (array) self::toPinyin($text, true);
575
        $result = array_map(function ($row) {
576
            return self::sub($row, 0, 1);
577
        }, $array);
578
        if (true === $returnArray) {
579
            return $result;
580 1
        } elseif (false === $returnArray) {
0 ignored issues
show
introduced by
The condition false === $returnArray is always true.
Loading history...
581
            return implode('', $result);
582 1
        } else {
583 1
            return implode((string) $returnArray, $result);
584 1
        }
585 1
    }
586 1
587 1
    /**
588
     * 隐藏部分文字
589 1
     *
590 1
     * - 只支持三种模式,例如:3?4、?3、3?,数字代表显示的字符数,默认模式为:3?4
591 1
     *
592 1
     * @param string $string
593 1
     * @param string $hideChar 被替换的字符,默认为:****
594 1
     * @param string $mode 替换模式,默认为:3?4,即保留前 3 字符,后 4 字符,隐藏中间
595
     *
596 1
     * @return string
597
     */
598
    public static function hide($string, $hideChar = '****', $mode = '3?4')
599 1
    {
600
        $length = self::length($string);
601
        $modeArray = self::split($mode);
602
        $modeCount = Arrays::count($modeArray);
603
        C::assertFalse(1 !== Arrays::count($modeArray, '?'), '模式错误,只允许有且仅有一个 ? 符,例如:3?4');
604
        if ($length <= array_sum($modeArray)) {
605
            return $string;
606
        }
607
        if (3 === Arrays::count($modeArray)) {
608
            C::assertTrue('?' === $modeArray[1], '模式错误,三段时,? 符必须在中间,例如:3?4');
609
            return self::sub($string, 0, $modeArray[0]) . $hideChar . self::sub($string, $length - $modeArray[2], $modeArray[2]);
0 ignored issues
show
Bug introduced by
$modeArray[0] of type string is incompatible with the type integer|null expected by parameter $length of icy2003\php\ihelpers\Strings::sub(). ( Ignorable by Annotation )

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

609
            return self::sub($string, 0, /** @scrutinizer ignore-type */ $modeArray[0]) . $hideChar . self::sub($string, $length - $modeArray[2], $modeArray[2]);
Loading history...
610
        } elseif (2 === $modeCount) {
611
            if ('?' === $modeArray[0]) {
612
                return $hideChar . self::sub($string, $length - $modeArray[1], $modeArray[1]);
613
            } else {
614
                return self::sub($string, 0, $modeArray[0]) . $hideChar;
615
            }
616
        } else {
617
            throw new Exception("支持模式有三种,例如:3?4、?3、3?");
618
        }
619
    }
620
621
    /**
622
     * 多次换行
623
     *
624
     * @param integer $num 换行次数
625
     *
626
     * @return string
627
     */
628
    public static function eol($num = 1)
629
    {
630
        return str_repeat(PHP_EOL, $num);
631
    }
632
633
    /**
634
     * 返回字符串占用行数
635
     *
636
     * @param string $string
637 50
     *
638
     * @return integer
639 50
     */
640
    public static function lineNumber($string)
641
    {
642
        $array = explode(PHP_EOL, $string);
643
        return Arrays::count($array);
644
    }
645
646
    /**
647
     * 字符串替换
648
     *
649
     * @param string $string
650
     * @param array $replaceArray 键值对替换
651
     * @param integer $count 如果给定,则引用返回替换次数
652
     *
653
     * @return string
654
     */
655
    public static function replace($string, $replaceArray, &$count = null)
656
    {
657
        return str_replace(array_keys($replaceArray), array_values($replaceArray), $string, $count);
658
    }
659
}
660