Failed Conditions
Pull Request — master (#3743)
by Adrien
14:08
created

Arabic::strSplit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 1
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
4
5
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
6
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
7
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
8
9
class Arabic
10
{
11
    use ArrayEnabled;
12
13
    private const ROMAN_LOOKUP = [
14
        'M' => 1000,
15
        'D' => 500,
16
        'C' => 100,
17
        'L' => 50,
18
        'X' => 10,
19
        'V' => 5,
20
        'I' => 1,
21
    ];
22
23
    /**
24
     * Recursively calculate the arabic value of a roman numeral.
25
     *
26
     * @param int $sum
27
     * @param int $subtract
28
     *
29
     * @return int
30
     */
31 17
    private static function calculateArabic(array $roman, &$sum = 0, $subtract = 0)
32
    {
33 17
        $numeral = array_shift($roman);
34 17
        if (!isset(self::ROMAN_LOOKUP[$numeral])) {
35 1
            throw new Exception('Invalid character detected');
36
        }
37
38 16
        $arabic = self::ROMAN_LOOKUP[$numeral];
39 16
        if (count($roman) > 0 && isset(self::ROMAN_LOOKUP[$roman[0]]) && $arabic < self::ROMAN_LOOKUP[$roman[0]]) {
40 12
            $subtract += $arabic;
41
        } else {
42 16
            $sum += ($arabic - $subtract);
43 16
            $subtract = 0;
44
        }
45
46 16
        if (count($roman) > 0) {
47 15
            self::calculateArabic($roman, $sum, $subtract);
48
        }
49
50 16
        return $sum;
51
    }
52
53 17
    /**
54
     * ARABIC.
55 17
     *
56
     * Converts a Roman numeral to an Arabic numeral.
57
     *
58 17
     * Excel Function:
59
     *        ARABIC(text)
60 17
     *
61
     * @param mixed $roman Should be a string, or can be an array of strings
62 17
     *
63
     * @return array|int|string the arabic numberal contrived from the roman numeral
64
     *         If an array of numbers is passed as the argument, then the returned result will also be an array
65
     *            with the same dimensions
66
     */
67
    public static function evaluate(mixed $roman)
68
    {
69
        if (is_array($roman)) {
70
            return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $roman);
71
        }
72
73
        // An empty string should return 0
74
        $roman = substr(trim(strtoupper((string) $roman)), 0, 255);
75
        if ($roman === '') {
76
            return 0;
77
        }
78
79 18
        // Convert the roman numeral to an arabic number
80
        $negativeNumber = $roman[0] === '-';
81 18
        if ($negativeNumber) {
82 17
            $roman = substr($roman, 1);
83
        }
84
85
        try {
86 18
            $arabic = self::calculateArabic(str_split($roman));
87 18
        } catch (Exception) {
88 1
            return ExcelError::VALUE(); // Invalid character detected
89
        }
90
91
        if ($negativeNumber) {
92 17
            $arabic *= -1; // The number should be negative
93 17
        }
94 2
95
        return $arabic;
96
    }
97
}
98