Passed
Push — master ( 8600e3...c5f6b1 )
by herry
04:49
created

Convert::toCn()   C

Complexity

Conditions 15
Paths 134

Size

Total Lines 35
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 15
eloc 26
c 2
b 0
f 0
nc 134
nop 3
dl 0
loc 35
rs 5.6333

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the mucts.com.
4
 *
5
 * This source file is subject to the MIT license that is bundled
6
 * with this source code in the file LICENSE.
7
 *
8
 * @version 1.0
9
 * @author herry<[email protected]>
10
 * @copyright © 2020 MuCTS.com All Rights Reserved.
11
 */
12
13
namespace MuCTS\Money\Chinese;
14
15
use Illuminate\Support\Arr;
16
use MuCTS\Money\Exceptions\InvalidArgumentException;
17
18
final class Convert
19
{
20
    private const DIGITAL = [
21
        0 => '零',
22
        1 => '壹',
23
        2 => '贰',
24
        3 => '叁',
25
        4 => '肆',
26
        5 => '伍',
27
        6 => '陆',
28
        7 => '柒',
29
        8 => '捌',
30
        9 => '玖',
31
    ];
32
33
    private const UNIT = [
34
        -4 => '毫',
35
        -3 => '厘',
36
        -2 => '分',
37
        -1 => '角',
38
        0 => '元',
39
        1 => '拾',
40
        2 => '佰',
41
        3 => '仟',
42
        4 => '万',
43
        8 => '亿',
44
        12 => '兆',
45
        16 => '京',
46
        20 => '垓',
47
        24 => '杼',
48
        28 => '穰',
49
        32 => '沟',
50
        36 => '涧',
51
        40 => '正',
52
        44 => '载',
53
        48 => '极'
54
    ];
55
56
    private const SYMBOL = [
57
        '-' => '负',
58
        '+' => '',
59
        '' => '整'
60
    ];
61
62
63
    /**
64
     * 金额转换成中文
65
     *
66
     * @param string|int|float $amount
67
     * @param string $prefix
68
     * @param string $cnPrefix
69
     * @return string
70
     */
71
    public static function toCn($amount, $prefix = '¥', string $cnPrefix = '人民币'): string
72
    {
73
        if (!preg_match(sprintf('/^(%s)?[+\-]?([1-9]\d{0,2}([,]?\d{3})*|0)(\.\d{0,4})?$/', $prefix), $amount)) {
74
            throw new InvalidArgumentException(sprintf('%s is not a valid chinese number text', $amount));
75
        }
76
        $amount = strtr($amount, [',' => '', $prefix => '']);
77
        list($integer, $decimals) = explode('.', strval($amount) . '.', 2);
78
        if (($len = strlen($integer)) > 48) {
79
            throw new InvalidArgumentException(sprintf('%s is not a valid chinese number text', $amount));
80
        }
81
        $integerStr = '';
82
        $i = $len;
83
        $unit = 0;
84
        while ($i) {
85
            $num = $integer[$len - $i--];
86
            if (in_array($num, array_keys(self::SYMBOL), true)) {
87
                $integerStr .= self::SYMBOL[$num];
88
                continue;
89
            }
90
            if ($num > 0 || Arr::exists(self::UNIT, $i) && $unit <= $i) {
91
                $integerStr .= $num > 0 || $i == 0 ? self::DIGITAL[$num] : '';
92
                $unit = Arr::exists(self::UNIT, $i) ? $i : $i % 4;
93
                $integerStr .= self::UNIT[$unit];
94
            }
95
        }
96
        $decimalStr = '';
97
        $len = strlen($decimals);
98
        for ($i = 0; $i < $len; $i++) {
99
            $num = $decimals[$i];
100
            if ($num > 0) {
101
                $decimalStr .= self::DIGITAL[$num] . self::UNIT[-1 - $i];
102
            }
103
        }
104
        $integerStr = strpos($integerStr, self::UNIT[0]) ? $integerStr : $integerStr . self::UNIT[0];
105
        return $cnPrefix . $integerStr . ($decimalStr != '' ? $decimalStr : self::SYMBOL['']);
106
    }
107
108
    /**
109
     * 中文金额转阿拉伯数字金额
110
     *
111
     * @param string $cnAmount
112
     * @param string $prefix
113
     * @param string $cnPrefix
114
     * @return string
115
     */
116
    public static function toDigit(string $cnAmount, string $prefix = '¥', string $cnPrefix = '人民币'): string
117
    {
118
        $amount = preg_replace("/^{$cnPrefix}/", '', $cnAmount);
119
        $amount = preg_replace('/' . self::UNIT[0] . self::SYMBOL[''] . '$/', self::UNIT[0], $amount);
120
        $amounts = mb_str_split($amount);
121
        $amount = $maxUnit = 0;
122
        // 断定是否是正数,默认是
123
        $plus = 1;
124
        $decimal = 0;
125
        $un = null;
126
        while ($chr = array_pop($amounts)) {
127
            if (($key = array_search($chr, self::DIGITAL)) !== false) {
128
                if (is_null($un)) {
129
                    throw new InvalidArgumentException(sprintf('%s is not a valid chinese number text', $cnAmount));
130
                }
131
                if ($un >= 0) {
132
                    $amount = gmp_add($amount, gmp_mul($key, $un < 0 ? 10 ** $un : gmp_pow('10', $un)));
133
                } else {
134
                    $decimal += $key * (10 ** $un);
135
                }
136
                $un = null;
137
            } elseif (($key = array_search($chr, self::UNIT)) !== false) {
138
                if (!is_null($un) && $un != 0) {
139
                    throw new InvalidArgumentException(sprintf('%s is not a valid chinese number text', $cnAmount));
140
                }
141
                $un = $key;
142
                $maxUnit = max($maxUnit, $un);
143
                $un = $maxUnit > $un ? $maxUnit + $un : $un;
144
            } elseif ($chr == self::SYMBOL['-']) {
145
                $plus = -1;
146
            } else {
147
                throw new InvalidArgumentException(sprintf('%s is not a valid chinese number text', $cnAmount));
148
            }
149
        }
150
        return $prefix . gmp_strval(gmp_mul($amount, $plus)) . ltrim(strval($decimal), '0');
151
    }
152
}