Passed
Push — master ( d2184e...ee1eb5 )
by Sebastian
04:46
created

NumberHelper   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 140
Duplicated Lines 0 %

Test Coverage

Coverage 81.48%

Importance

Changes 0
Metric Value
eloc 68
dl 0
loc 140
ccs 44
cts 54
cp 0.8148
rs 10
c 0
b 0
f 0
wmc 29

6 Methods

Rating   Name   Duplication   Size   Complexity  
A extractNumber() 0 6 2
A roman2Dec() 0 23 6
A getCompareNumber() 0 12 6
B evaluateStringPluralism() 0 23 9
A dec2roman() 0 13 3
A isRomanNumber() 0 9 3
1
<?php
2
/*
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
 * citeproc-php
4
 *
5
 * @link        http://github.com/seboettg/citeproc-php for the source repository
6
 * @copyright   Copyright (c) 2016 Sebastian Böttger.
7
 * @license     https://opensource.org/licenses/MIT
8
 */
9
10
namespace Seboettg\CiteProc\Util;
11
12
/**
13
 * Class Number
14
 * @package Seboettg\CiteProc\Util
1 ignored issue
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
15
 *
16
 * @author Sebastian Böttger <[email protected]>
17
 */
3 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
18
class NumberHelper
19
{
20
21
    const PATTERN_ORDINAL = "/\d+(st|nd|rd|th)?\.?$/";
22
23
    const PATTERN_ROMAN = "/^[ivxlcdm]+\.?$/i";
24
25
    const PATTERN_AFFIXES = "/^[a-z]?\d+[a-z]?$/i";
26
27
    const PATTERN_COMMA_AMPERSAND_RANGE = "/\d*([\s?\-&+,;\s])+\d+/";
28
29
    const ROMAN_NUMERALS = [
30
        ["", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"],
31
        ["", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"],
32
        ["", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"],
33
        ["", "m", "mm", "mmm", "mmmm", "mmmmm"]
34
    ];
35
36
    const ROMAN_DIGITS = [
37
        "M" => 1000,
38
        "D" => 500,
39
        "C" => 100,
40
        "L" => 50,
41
        "X" => 10,
42
        "V" => 5,
43
        "I" => 1
44
    ];
45
46
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
47
     * @return \Closure
48
     */
49
    public static function getCompareNumber()
50
    {
51
        return function($numA, $numB, $order) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
52
            if (is_numeric($numA) && is_numeric($numB)) {
53
                $ret = $numA - $numB;
54
            } else {
55
                $ret = strcasecmp($numA, $numB);
56
            }
57
            if ("descending" === $order) {
58
                return $ret > 0 ? -1 : 1;
59
            }
60
            return $ret > 0 ? 1 : -1;
61
        };
62
    }
63
64
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $num should have a doc-comment as per coding-style.
Loading history...
65
     * @param $num
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
66
     * @return string
1 ignored issue
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
67
     */
68 4
    public static function dec2roman($num)
69
    {
70 4
        $ret = "";
71 4
        if ($num < 6000) {
72
73 4
            $numStr = strrev($num);
74 4
            $len = strlen($numStr);
75 4
            for ($pos = 0; $pos < $len; $pos++) {
76 4
                $n = $numStr[$pos];
77 4
                $ret = self::ROMAN_NUMERALS[$pos][$n] . $ret;
78
            }
79
        }
80 4
        return $ret;
81
    }
82
83
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $romanNumber should have a doc-comment as per coding-style.
Loading history...
84
     * @param $romanNumber
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
85
     * @return int|mixed
1 ignored issue
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
86
     */
87 1
    public static function roman2Dec($romanNumber)
88
    {
89 1
        if (is_numeric($romanNumber)) {
90
            return 0;
91
        }
92
93 1
        $values = [];
94
        // Convert the string to an array of roman values:
95 1
        for ($i = 0; $i < strlen($romanNumber); ++$i) {
96 1
            $char = strtoupper($romanNumber{$i});
97 1
            if (self::ROMAN_DIGITS[$char] !== null) {
98 1
                $values[] = self::ROMAN_DIGITS[$char];
99
            }
100
        }
101
102 1
        $sum = 0;
103 1
        while ($current = current($values)) {
104 1
            $next = next($values);
105 1
            $next > $current ? $sum += $next - $current + 0 * next($values) : $sum += $current;
106
        }
107
108
        // Return the value:
109 1
        return $sum;
110
    }
111
112 2
    public static function isRomanNumber($str)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function isRomanNumber()
Loading history...
113
    {
114 2
        for ($i = 0; $i < strlen($str); ++$i) {
115 2
            $char = strtoupper($str{$i});
116 2
            if (!in_array($char, array_keys(self::ROMAN_DIGITS))) {
117 2
                return false;
118
            }
119
        }
120 2
        return true;
121
    }
122
123
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $str should have a doc-comment as per coding-style.
Loading history...
124
     * @param $str
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
125
     * @return string
1 ignored issue
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
126
     */
127 1
    public static function evaluateStringPluralism($str)
128
    {
129 1
        $plural = 'single';
130 1
        if (!empty($str)) {
131 1
            $ranges = preg_split("/[-–&,]/", $str);
132 1
            if (count($ranges) > 1) {
0 ignored issues
show
Bug introduced by
It seems like $ranges can also be of type false; however, parameter $var of count() does only seem to accept Countable|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

132
            if (count(/** @scrutinizer ignore-type */ $ranges) > 1) {
Loading history...
133
134 1
                $isRange = 1;
135 1
                foreach ($ranges as $range) {
136 1
                    if (NumberHelper::isRomanNumber(trim($range)) || is_numeric(trim($range))) {
137 1
                        $isRange &= 1;
138
                    }
139
                }
140 1
                if ($isRange == 1) {
141 1
                    return 'multiple';
142
                }
143
            } else {
144 1
                if (is_numeric($str) || NumberHelper::isRomanNumber($str)) {
145 1
                    return 'single';
146
                }
147
            }
148
        }
149
        return $plural;
150
    }
151
152 48
    public static function extractNumber($string)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function extractNumber()
Loading history...
153
    {
154 48
        if (preg_match("/(\d+)[^\d]*$/", $string, $match)) {
155 48
            return $match[1];
156
        }
157 3
        return $string;
158
    }
159
}