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.
Completed
Push — master ( 40d637...486f11 )
by t
07:13 queued 23s
created

Strings::lineNumber()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
c 2
b 0
f 0
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 icy2003\php\I;
13
14
/**
15
 * 字符串类
16
 *
17
 * @test icy2003\php_tests\ihelpers\StringsTest
18
 */
19
class Strings
20
{
21
22
    /**
23
     * 返回字符串的字节长
24
     *
25
     * - 一个中文等于 3 字节
26
     *
27
     * @param string $string
28
     *
29
     * @return integer
30
     *
31
     * @tested
32
     */
33
    public static function byteLength($string)
34
    {
35
        return mb_strlen($string, '8bit');
36
    }
37
    /**
38
     * 返回字符个数
39
     *
40
     * - 一个中文就是 1 个
41
     *
42
     * @param string $string
43
     *
44
     * @return integer
45
     *
46
     * @tested
47
     */
48
    public static function length($string)
49
    {
50
        return mb_strlen($string, 'UTF-8');
51
    }
52
53
    /**
54
     * 随机数种子(数字)
55
     */
56
    const STRINGS_RANDOM_NUMBER = '0123456789';
57
58
    /**
59
     * 随机数种子(小写字母)
60
     */
61
    const STRINGS_RANDOM_LOWERCASE = 'abcdefghijklmnopqrstuvwxyz';
62
63
    /**
64
     * 随机数种子(大写字母)
65
     */
66
    const STRINGS_RANDOM_UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
67
68
    /**
69
     * 生成随机字符串
70
     *
71
     * @param integer $length 随机字符串的长度,默认 32
72
     * @param string $chars 字符列表,默认为0-9和大小写字母
73
     *
74
     * @return string
75
     *
76
     * @test
77
     */
78
    public static function random($length = 32, $chars = self::STRINGS_RANDOM_NUMBER . self::STRINGS_RANDOM_LOWERCASE . self::STRINGS_RANDOM_UPPERCASE)
79
    {
80
        $str = '';
81
        for ($i = 0; $i < $length; ++$i) {
82
            $str .= mb_substr($chars, mt_rand(0, self::length($chars) - 1), 1);
83
        }
84
85
        return $str;
86
    }
87
88
    /**
89
     * 小驼峰转化成下划线(如需要大写下划线,用 strtoupper 转化即可)
90
     *
91
     * @param string $string
92
     *
93
     * @return string
94
     *
95
     * @tested
96
     */
97
    public static function toUnderline($string)
98
    {
99
        return strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $string));
100
    }
101
102
    /**
103
     * 下划线转化为小驼峰(如需要大驼峰,用 ucfirst 转化即可)
104
     *
105
     * @param string $string
106
     *
107
     * @return string
108
     *
109
     * @tested
110
     */
111
    public static function toCamel($string)
112
    {
113
        return lcfirst(preg_replace_callback('/_+([a-z0-9_\x7f-\xff])/', function ($matches) {
114
            return ucfirst($matches[1]);
115
        }, strtolower($string)));
116
    }
117
118
    /**
119
     * 格式化成标题格式(每个单词首字母大写)
120
     *
121
     * @param string $string
122
     *
123
     * @return string
124
     *
125
     * @tested
126
     */
127
    public static function toTitle($string)
128
    {
129
        return mb_convert_case($string, MB_CASE_TITLE, 'UTF-8');
130
    }
131
132
    /**
133
     * 检查字符串是否以某字符串开头
134
     *
135
     * @param string $string
136
     * @param string $search 待搜索子字符串
137
     *
138
     * @return boolean
139
     *
140
     * @tested
141
     */
142
    public static function isStartsWith($string, $search)
143
    {
144
        return (string) $search !== "" && mb_strpos($string, $search) === 0;
145
    }
146
147
    /**
148
     * 检查字符串是否以某字符串结尾
149
     *
150
     * @param string $string
151
     * @param string $search 待搜索子字符串
152
     *
153
     * @return boolean
154
     *
155
     * @tested
156
     */
157
    public static function isEndsWith($string, $search)
158
    {
159
        return (string) $search !== "" && mb_substr($string, -static::length($search)) === $search;
160
    }
161
162
    /**
163
     * 检查字符串中是否包含某字符串
164
     *
165
     * @param string $string
166
     * @param string $search 待搜索子字符串
167
     * @param integer $pos 如果找到子串,则引用出子串的起始位置
168
     *
169
     * @return boolean
170
     *
171
     * @tested
172
     */
173
    public static function isContains($string, $search, &$pos = null)
174
    {
175
        return (string) $search !== "" && ($pos = mb_strpos($string, $search)) !== false;
176
    }
177
178
    /**
179
     * 在字符串里找子串的前部分
180
     *
181
     * @param string $string
182
     * @param string $search
183
     * @param integer $pos 如果找到子串,则引用出子串的起始位置
184
     *
185
     * @return string
186
     *
187
     * @tested
188
     */
189
    public static function partBefore($string, $search, &$pos = null)
190
    {
191
        if (self::isContains($string, $search, $pos)) {
192
            return mb_substr($string, 0, $pos);
193
        }
194
        return "";
195
    }
196
197
    /**
198
     * 在字符串里找子串的后部分
199
     *
200
     * @param string $string
201
     * @param string $search
202
     * @param integer $pos 如果找到子串,则引用出子串的起始位置
203
     *
204
     * @return string
205
     *
206
     * @tested
207
     */
208
    public static function partAfter($string, $search, &$pos = null)
209
    {
210
        if (self::isContains($string, $search, $pos)) {
211
            return mb_substr($string, $pos + self::length($search), self::length($string) - 1);
212
        }
213
        return "";
214
    }
215
216
    /**
217
     * 反转字符串,支持中文
218
     *
219
     * @param string $string
220
     *
221
     * @return string
222
     *
223
     * @tested
224
     */
225
    public static function reverse($string)
226
    {
227
        return implode('', array_reverse(self::split($string)));
228
    }
229
230
    /**
231
     * 把字符串打散为数组
232
     *
233
     * @param string $string
234
     *
235
     * @return array
236
     *
237
     * @tested
238
     */
239
    public static function split($string)
240
    {
241
        return preg_split('/(?<!^)(?!$)/u', $string);
0 ignored issues
show
Bug Best Practice introduced by
The expression return preg_split('/(?<!^)(?!$)/u', $string) could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
242
    }
243
244
    /**
245
     * 拆分成数组
246
     *
247
     * @param array|string $mixed 数组或者字符串
248
     * @param string $delimiter 分隔符,默认英文逗号(,)
249
     * @param boolean $combine 是否合并相同元素,默认 false,即不合并
250
     *
251
     * @return array
252
     *
253
     * @tested
254
     */
255 3
    public static function toArray($mixed, $delimiter = ',', $combine = false)
256
    {
257 3
        if (is_array($mixed)) {
258 3
            $mixed = implode($delimiter, $mixed);
259
        }
260 3
        $array = explode($delimiter, $mixed);
261 3
        if (true === $combine) {
262
            $array = Arrays::toPart($array);
263
        }
264 3
        return $array;
265
    }
266
267
    /**
268
     * 返回字符串的子串
269
     *
270
     * @param string $string
271
     * @param integer $start 起始位置
272
     * @param integer|null $length 子串长度,默认为 null,即返回剩下的部分
273
     *
274
     * @return string
275
     *
276
     * @tested
277
     */
278
    public static function sub($string, $start, $length = null)
279
    {
280
        return mb_substr($string, $start, $length);
281
    }
282
283
    /**
284
     * 字符串转数字
285
     *
286
     * - 正则为 `/^\d\.*\d*[e|E]/` 的字符串会……,这是 PHP 特性!如果你不喜欢 PHP,右上角
287
     *
288
     * @param string $string
289
     *
290
     * @return double
291
     *
292
     * @tested
293
     */
294
    public static function toNumber($string)
295
    {
296
        return (double) $string;
297
    }
298
299
    /**
300
     * 用回调将分隔符拆分出来的字符串执行后,用分隔符合并回去
301
     *
302
     * @param callback $callback 回调
303
     * @param string $string
304
     * @param string $delimiter 分隔符,默认英文逗号(,)
305
     *
306
     * @return string
307
     */
308
    public static function map($callback, $string, $delimiter = ',')
309
    {
310
        $arr = [];
311
        $parts = explode($delimiter, $string);
312
        foreach ($parts as $part) {
313
            $arr[] = I::trigger($callback, [$part]);
314
        }
315
        return implode($delimiter, $arr);
316
    }
317
318
    /**
319
     * 重复一个字符若干次
320
     *
321
     * @param string $char
322
     * @param integer $num
323
     * @param integer $maxLength 最大重复次数,默认不限制
324
     *
325
     * @return string
326
     */
327
    public static function repeat($char, $num, $maxLength = null)
328
    {
329
        $length = null === $maxLength ? $num : min($maxLength, $num);
330
        return str_repeat($char, $length);
331
    }
332
333
    /**
334
     * 生成密码 hash
335
     *
336
     * @param string $password 原始密码
337
     * @param integer $cost
338
     *
339
     * @return string
340
     */
341
    public static function generatePasswordHash($password, $cost = null)
342
    {
343
        null === $cost && $cost = 13;
344
        // PHP 5 >= 5.5.0, PHP 7
345
        if (function_exists('password_hash')) {
346
            return password_hash($password, PASSWORD_DEFAULT, ['cost' => $cost]);
347
        }
348
        if ($cost < 4 || $cost > 31) {
349
            throw new Exception('cost 必须大于等于 4,小于等于 31');
0 ignored issues
show
Bug introduced by
The type icy2003\php\ihelpers\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
350
        }
351
        $salt = sprintf('$2y$%02d$', $cost);
352
        $salt .= str_replace('+', '.', substr(base64_encode(self::random(20)), 0, 22));
353
        $hash = crypt($password, $salt);
354
        if (!is_string($hash) || strlen($hash) !== 60) {
355
            throw new Exception('未知错误');
356
        }
357
        return $hash;
358
    }
359
360
    /**
361
     * 验证密码
362
     *
363
     * @param string $password 原始密码
364
     * @param string $hash HASH 后的密码,需配合 Strings::generatePasswordHash
365
     *
366
     * @return boolean
367
     */
368
    public static function validatePassword($password, $hash)
369
    {
370
        if (!is_string($password) || $password === '') {
0 ignored issues
show
introduced by
The condition is_string($password) is always true.
Loading history...
371
            return false;
372
        }
373
        $matches = [];
374
        if (!preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hash, $matches)
375
            || $matches[1] < 4
376
            || $matches[1] > 30) {
377
            return false;
378
        }
379
        // PHP 5 >= 5.5.0, PHP 7
380
        if (function_exists('password_verify')) {
381
            return password_verify($password, $hash);
382
        }
383
384
        $test = crypt($password, $hash);
385
        $n = strlen($test);
386
        if ($n !== 60) {
387
            return false;
388
        }
389
        // PHP 5 >= 5.6.0, PHP 7
390
        if (function_exists('hash_equals')) {
391
            return hash_equals($test, $hash);
392
        }
393
394
        $test .= '\0';
395
        $hash .= '\0';
396
        $expectedLength = self::byteLength($test);
397
        $actualLength = self::byteLength($hash);
398
        $diff = $expectedLength - $actualLength;
399
        for ($i = 0; $i < $actualLength; $i++) {
400
            $diff |= (ord($hash[$i]) ^ ord($test[$i % $expectedLength]));
401
        }
402
403
        return $diff === 0;
404
    }
405
406
    /**
407
     * 字符串转成变量
408
     *
409
     * - 变量是被如:{{}}括起来的字符串
410
     * - 例如:{{var}}
411
     *
412
     * @param string $name
413
     * @param array $boundary 边界符,默认 ['{{', '}}']
414
     *
415
     * @return string
416
     */
417
    public static function toVariable($name, $boundary = ['{{', '}}'])
418
    {
419
        if (is_string($boundary)) {
0 ignored issues
show
introduced by
The condition is_string($boundary) is always false.
Loading history...
420
            $boundary = [$boundary, $boundary];
421
        }
422
        return self::isContains($name, $boundary[0]) ? $name : $boundary[0] . $name . $boundary[1];
423
    }
424
425
    /**
426
     * 判断一个字符串是否是变量
427
     *
428
     * @param string $name
429
     * @param array $boundary 边界符,默认 ['{{', '}}']
430
     *
431
     * @return boolean
432
     */
433
    public static function isVariable($name, $boundary = ['{{', '}}'])
434
    {
435
        return self::isStartsWith($name, $boundary[0]) && self::isEndsWith($name, $boundary[1]);
436
    }
437
438
    /**
439
     * 计算包含变量的字符串
440
     *
441
     * @param string $text
442
     * @param array $array 键值对形式:[{{键}} => 值]。如果键不是变量,则不会替换进 $text
443
     * @param array $boundary 边界符,默认 ['{{', '}}']
444
     *
445
     * @return string
446
     */
447
    public static function fromVariable($text, $array, $boundary = ['{{', '}}'])
448
    {
449
        $data = [];
450
        foreach ($array as $name => $value) {
451
            self::isVariable($name, $boundary) && $data[$name] = $value;
452
        }
453
        return str_replace(array_keys($data), array_values($data), $text);
454
    }
455
456
    /**
457
     * 判断两个字符串像不像
458
     *
459
     * - 图形验证码里经常有人把 o 看成 0,所以……
460
     * - 例如:hello 和 hell0 看起来是像的 (-w-)o~
461
     *
462
     * @param string $string1 第一个字符串
463
     * @param string $string2 第二个字符串
464
     * @param array $array 看起来像的字符的列表,默认 ['0o', 'yv', 'ij', '1l']
465
     *
466
     * @return boolean
467
     */
468
    public static function looksLike($string1, $string2, $array = ['0oO', 'yv', 'ij', '1lI'])
469
    {
470
        $array1 = self::split($string1);
471
        $array2 = self::split($string2);
472
        foreach ($array1 as $index => $char1) {
473
            $char1 = strtolower($char1);
474
            $char2 = strtolower($array2[$index]);
475
            $isEqual = false;
476
            if ($char1 == $char2) {
477
                $isEqual = true;
478
            }
479
            foreach ($array as $row) {
480
                if (self::isContains($row, $char1) && self::isContains($row, $char2)) {
481
                    $isEqual = true;
482
                    break;
483
                }
484
            }
485
            if (false === $isEqual) {
486
                break;
487
            }
488
        }
489
        return $isEqual;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $isEqual seems to be defined by a foreach iteration on line 472. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
490
    }
491
492
    /**
493
     * 拼音编码对应表
494
     *
495
     * @var array
496
     */
497
    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];
498
499
    /**
500
     * 字符串转拼音
501
     *
502
     * @param string $text
503
     * @param boolean $returnArray 是否拆分返回数组,默认 false
504
     *
505
     * @return mixed
506
     */
507
    public static function toPinyin($text, $returnArray = false)
508
    {
509
        $text = Charset::convertTo($text, 'GB2312');
510
        $result = [];
511
        $length = strlen($text);
512
        for ($i = 0; $i < $length; $i++) {
513
            $p = ord(substr($text, $i, 1));
514
            if ($p > 160) {
515
                $p = $p * 256 + ord(substr($text, ++$i, 1)) - 65536;
516
            }
517
            if ($p > 0 && $p < 160) {
518
                $result[] = chr($p);
519
            } elseif ($p < -20319 || $p > -10247) {
520
                return '';
521
            } else {
522
                $res = '';
523
                foreach (self::$__pinyin as $pin => $code) {
524
                    if ($code > $p) {
525
                        break;
526
                    }
527
                    $res = $pin;
528
                }
529
                $result[] = $res;
530
            }
531
        }
532
        return true === $returnArray ? $result : implode('', $result);
533
    }
534
535
    /**
536
     * 字符串转拼音首字母
537
     *
538
     * @param string $text
539
     * @param boolean $returnArray 是否拆分返回数组,默认 false
540
     *
541
     * @return mixed
542
     */
543
    public static function toPinyinFirst($text, $returnArray = false)
544
    {
545
        $array = self::toPinyin($text, true);
546
        $result = array_map(function ($row) {
547
            return self::sub($row, 0, 1);
548
        }, $array);
0 ignored issues
show
Bug introduced by
It seems like $array can also be of type string; however, parameter $arr1 of array_map() does only seem to accept 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

548
        }, /** @scrutinizer ignore-type */ $array);
Loading history...
549
        return true === $returnArray ? $result : implode('', $result);
550
    }
551
552
    /**
553
     * 隐藏部分文字
554
     *
555
     * - 只支持三种模式,例如:3?4、?3、3?,数字代表显示的字符数,默认模式为:3?4
556
     *
557
     * @param string $string
558
     * @param string $hideChar 被替换的字符,默认为:****
559
     * @param string $mode 替换模式,默认为:3?4,即保留前 3 字符,后 4 字符,隐藏中间
560
     *
561
     * @return string
562
     */
563
    public static function hide($string, $hideChar = '****', $mode = '3?4')
564
    {
565
        $length = self::length($string);
566
        $modeArray = self::split($mode);
567
        $modeCount = Arrays::count($modeArray);
568
        if (1 !== Arrays::count($modeArray, '?')) {
569
            throw new Exception("模式错误,只允许有且仅有一个 ? 符,例如:3?4");
570
        }
571
        if ($length <= array_sum($modeArray)) {
572
            return $string;
573
        }
574
        if (3 === Arrays::count($modeArray)) {
575
            if ('?' === $modeArray[1]) {
576
                return self::sub($string, 0, $modeArray[0]) . $hideChar . self::sub($string, $length - $modeArray[2], $modeArray[2]);
577
            } else {
578
                throw new Exception("模式错误,三段时,? 符必须在中间,例如:3?4");
579
            }
580
        } elseif (2 === $modeCount) {
581
            if ('?' === $modeArray[0]) {
582
                return $hideChar . self::sub($string, $length - $modeArray[1], $modeArray[1]);
583
            } else {
584
                return self::sub($string, 0, $modeArray[0]) . $hideChar;
585
            }
586
        } else {
587
            throw new Exception("支持模式有三种,例如:3?4、?3、3?");
588
        }
589
    }
590
591
    /**
592
     * 多次换行
593
     *
594
     * @param integer $num 换行次数
595
     *
596
     * @return string
597
     */
598
    public static function eol($num = 1)
599
    {
600
        return str_repeat(PHP_EOL, $num);
601
    }
602
603
    /**
604
     * 返回字符串占用行数
605
     *
606
     * @param string $string
607
     *
608
     * @return integer
609
     */
610
    public static function lineNumber($string)
611
    {
612
        $array = explode(PHP_EOL, $string);
613
        return Arrays::count($array);
614
    }
615
}
616