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.
Passed
Push — master ( e40e2c...76ed50 )
by Carlos
12:49
created

Pinyin::formatTone()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 13
c 0
b 0
f 0
nc 6
nop 2
dl 0
loc 24
ccs 7
cts 7
cp 1
crap 6
rs 9.2222
1
<?php
2
3
namespace Overtrue\Pinyin;
4
5
use InvalidArgumentException;
6
7
defined('PINYIN_DEFAULT') || define('PINYIN_DEFAULT', 4096);
8
defined('PINYIN_TONE') || define('PINYIN_TONE', 2);
9
defined('PINYIN_NO_TONE') || define('PINYIN_NO_TONE', 4);
10
defined('PINYIN_ASCII_TONE') || define('PINYIN_ASCII_TONE', 8);
11
defined('PINYIN_NAME') || define('PINYIN_NAME', 16);
12
defined('PINYIN_KEEP_NUMBER') || define('PINYIN_KEEP_NUMBER', 32);
13
defined('PINYIN_KEEP_ENGLISH') || define('PINYIN_KEEP_ENGLISH', 64);
14
defined('PINYIN_UMLAUT_V') || define('PINYIN_UMLAUT_V', 128);
15
defined('PINYIN_KEEP_PUNCTUATION') || define('PINYIN_KEEP_PUNCTUATION', 256);
16
17
class Pinyin
18
{
19
    private const SEGMENTS_COUNT = 10;
20
    private const WORDS_PATH = __DIR__.'/../data/words-%s.php';
21
    private const SURNAMES_PATH = __DIR__.'/../data/surnames.php';
22
23 1
    protected array $punctuations = [
24 1
        ',' => ',',
25 1
        '。' => '.',
26
        '!' => '!',
27
        '?' => '?',
28
        ':' => ':',
29
        '“' => '"',
30
        '”' => '"',
31
        '‘' => "'",
32
        '’' => "'",
33
        '_' => '_',
34
    ];
35
36
    public function __construct(protected int $defaultOptions = \PINYIN_DEFAULT)
37
    {
38
    }
39
40
    public function convert(string $string, int $option = null): array
41
    {
42
        $option = $option ?? $this->defaultOptions;
43
        $pinyin = $this->transform($string, $option);
44
45
        return $this->splitPinyin($pinyin, $option);
46
    }
47
48
    public function name(string $name, int $option = null): array
49
    {
50
        $option = ($option ?? $this->defaultOptions) | \PINYIN_NAME;
51
52
        $pinyin = $this->transform($name, $option);
53
54
        return $this->splitPinyin($pinyin, $option);
55
    }
56
57
    public function permalink(string $string, string $delimiter = '-', string $option = null): string
58
    {
59
        $option = $option ?? $this->defaultOptions;
60
61
        if (\is_int($delimiter)) {
0 ignored issues
show
introduced by
The condition is_int($delimiter) is always false.
Loading history...
62 21
            list($option, $delimiter) = [$delimiter, '-'];
63
        }
64 21
65 21
        if (!in_array($delimiter, ['_', '-', '.', ''], true)) {
66
            throw new InvalidArgumentException("Delimiter must be one of: '_', '-', '', '.'.");
67
        }
68
69
        return implode($delimiter, $this->convert($string, $option | \PINYIN_KEEP_NUMBER | \PINYIN_KEEP_ENGLISH));
70
    }
71
72
    public function abbr(string $string, string $delimiter = '', int $option = null): string
73
    {
74
        $option = $option ?? $this->defaultOptions;
75 10
76
        if (\is_int($delimiter)) {
0 ignored issues
show
introduced by
The condition is_int($delimiter) is always false.
Loading history...
77 10
            list($option, $delimiter) = [$delimiter, ''];
78
        }
79 10
80
        return implode($delimiter, array_map(function ($pinyin) {
81
            return \is_numeric($pinyin) || preg_match('/\d+/', $pinyin) ? $pinyin : mb_substr($pinyin, 0, 1);
82
        }, $this->convert($string, $option | \PINYIN_NO_TONE)));
83
    }
84
85
    public function phrase(string $string, string|int $delimiter = ' ', int|string $option = null): string
86
    {
87
        $option = $option ?? $this->defaultOptions;
88
89
        if (\is_int($delimiter)) {
90 2
            list($option, $delimiter) = [$delimiter, ' '];
91
        }
92 2
93
        return implode($delimiter, $this->convert($string, $option));
0 ignored issues
show
Bug introduced by
It seems like $option can also be of type string; however, parameter $option of Overtrue\Pinyin\Pinyin::convert() does only seem to accept integer|null, 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

93
        return implode($delimiter, $this->convert($string, /** @scrutinizer ignore-type */ $option));
Loading history...
94 2
    }
95
96
    public function sentence(string $string, string|int $delimiter = ' ', int|string $option = null): string
97
    {
98
        $option = $option ?? $this->defaultOptions;
99
100
        if (\is_int($delimiter)) {
101
            list($option, $delimiter) = [$delimiter, ' '];
102
        }
103
104
        return implode($delimiter, $this->convert($string, $option | \PINYIN_KEEP_PUNCTUATION | \PINYIN_KEEP_ENGLISH | \PINYIN_KEEP_NUMBER));
105 2
    }
106
107 2
    public function transform(string $string, string $option = null): string
108 2
    {
109
        $option = $option ?? $this->defaultOptions;
110
        $string = $this->prepare($string, $option);
0 ignored issues
show
Bug introduced by
It seems like $option can also be of type string; however, parameter $option of Overtrue\Pinyin\Pinyin::prepare() does only seem to accept integer, 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

110
        $string = $this->prepare($string, /** @scrutinizer ignore-type */ $option);
Loading history...
111 2
112
        if ($this->hasOption($option, \PINYIN_NAME)) {
0 ignored issues
show
Bug introduced by
It seems like $option can also be of type string; however, parameter $option of Overtrue\Pinyin\Pinyin::hasOption() does only seem to accept integer, 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

112
        if ($this->hasOption(/** @scrutinizer ignore-type */ $option, \PINYIN_NAME)) {
Loading history...
113
            $string = $this->transformSurname($string);
114
        }
115
116
        for ($i = 0; $i < self::SEGMENTS_COUNT; $i++) {
117
            $string = strtr($string, require sprintf(self::WORDS_PATH, $i));
118
        }
119
120
        return $string;
121
    }
122 2
123
    protected function transformSurname(string $name): string
124
    {
125 2
        $surnames = require self::SURNAMES_PATH;
126 2
127
        foreach ($surnames as $surname => $pinyin) {
128
            if (\str_starts_with($name, $surname)) {
129
                return $pinyin . \mb_substr($name, \mb_strlen($surname));
130
            }
131
        }
132
133
        return $name;
134
    }
135
136
    protected function splitPinyin(string $pinyin, int $option): array
137
    {
138 2
        $split = array_filter(preg_split('/\s+/i', $pinyin));
139
140 2
        if (!$this->hasOption($option, \PINYIN_TONE)) {
141
            foreach ($split as $index => $pinyin) {
142
                $split[$index] = $this->formatTone($pinyin, $option);
143
            }
144
        }
145
146
        return array_values($split);
147
    }
148
149
    protected function hasOption(int $option, int $check): bool
150
    {
151 9
        return ($option & $check) === $check;
152
    }
153 9
154 9
    protected function prepare(string $string, int $option): string
155 9
    {
156
        $string = preg_replace_callback('~[a-z0-9_-]+~i', function ($matches) {
157 9
            return "\t" . $matches[0];
158
        }, $string);
159 9
160 9
        $regex = ['\p{Han}', '\p{Z}', '\p{M}', "\t"];
161
162 9
        if ($this->hasOption($option, \PINYIN_KEEP_NUMBER)) {
163
            $regex[] = '0-9';
164
        }
165
166
        if ($this->hasOption($option, \PINYIN_KEEP_ENGLISH)) {
167
            $regex[] = 'a-zA-Z';
168
        }
169
170
        if ($this->hasOption($option, \PINYIN_KEEP_PUNCTUATION)) {
171
            $punctuations = \array_merge($this->punctuations, ["\t" => ' ', '  ' => ' ']);
172 1
            $string = \trim(\str_replace(\array_keys($punctuations), $punctuations, $string));
173
            $regex[] = \preg_quote(\implode(\array_merge(\array_keys($this->punctuations), $this->punctuations)), '~');
174 1
        }
175
176 1
        return \preg_replace(\sprintf('~[^%s]~u', \implode($regex)), '', $string);
177
    }
178
179
    protected function formatTone(string $pinyin, int $option = \PINYIN_NO_TONE): string
180
    {
181
        $replacements = [
182
            'üē' => ['ue', 1], 'üé' => ['ue', 2], 'üě' => ['ue', 3], 'üè' => ['ue', 4],
183
            'ā' => ['a', 1], 'ē' => ['e', 1], 'ī' => ['i', 1], 'ō' => ['o', 1], 'ū' => ['u', 1], 'ǖ' => ['yu', 1],
184 21
            'á' => ['a', 2], 'é' => ['e', 2], 'í' => ['i', 2], 'ó' => ['o', 2], 'ú' => ['u', 2], 'ǘ' => ['yu', 2],
185
            'ǎ' => ['a', 3], 'ě' => ['e', 3], 'ǐ' => ['i', 3], 'ǒ' => ['o', 3], 'ǔ' => ['u', 3], 'ǚ' => ['yu', 3],
186 21
            'à' => ['a', 4], 'è' => ['e', 4], 'ì' => ['i', 4], 'ò' => ['o', 4], 'ù' => ['u', 4], 'ǜ' => ['yu', 4],
187 20
        ];
188
189 20
        foreach ($replacements as $unicode => $replacement) {
190 20
            if (\str_contains($pinyin, $unicode)) {
191 20
                $umlaut = $replacement[0];
192
193 21
                // https://zh.wikipedia.org/wiki/%C3%9C
194
                if ($this->hasOption($option, \PINYIN_UMLAUT_V) && 'yu' == $umlaut) {
195
                    $umlaut = 'v';
196
                }
197
198
                $pinyin = \str_replace($unicode, $umlaut, $pinyin) . ($this->hasOption($option, PINYIN_ASCII_TONE) ? $replacement[1] : '');
199
            }
200
        }
201
202
        return $pinyin;
203 21
    }
204
}
205