Issues (662)

src/Numbers/NumberPatternParser.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace ICanBoogie\CLDR\Numbers;
4
5
use function explode;
6
use function preg_match;
7
use function str_replace;
8
use function strpos;
9
use function strrpos;
10
use function substr;
11
12
/**
13
 * @link https://unicode.org/reports/tr35/tr35-numbers.html#Number_Pattern_Character_Definitions
14
 *
15
 * @phpstan-type PatternArray array{
16
 *      positive_prefix: string,
17
 *      positive_suffix: string,
18
 *      negative_prefix: string,
19
 *      negative_suffix: string,
20
 *      multiplier: int,
21
 *      decimal_digits: int,
22
 *      max_decimal_digits: int,
23
 *      integer_digits: int,
24
 *      group_size1: int,
25
 *      group_size2: int
26
 *  }
27
 */
28
final class NumberPatternParser
29
{
30
    public const PATTERN_REGEX = '/^(.*?)[#,\.0]+(.*?)$/';
31
32
    /**
33
     * @var array<string, int|string>
34
     */
35
    private static array $initial_format = [
36
37
        'positive_prefix' => '',
38
        'positive_suffix' => '',
39
        'negative_prefix' => '',
40
        'negative_suffix' => '',
41
        'multiplier' => 1,
42
        'decimal_digits' => 0,
43
        'max_decimal_digits' => 0,
44
        'integer_digits' => 0,
45
        'group_size1' => 0,
46
        'group_size2' => 0
47
48
    ];
49
50
    /**
51
     * Parses a given string pattern.
52
     *
53
     * @param string $pattern
54
     *
55
     * @return PatternArray
0 ignored issues
show
The type ICanBoogie\CLDR\Numbers\PatternArray was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
56
     */
57
    public static function parse(string $pattern): array
58
    {
59
        $format = self::$initial_format;
60
61
        self::parse_multiple_patterns($pattern, $format);
62
        self::parse_multiplier($pattern, $format);
63
        self::parse_decimal_part($pattern, $format);
64
        self::parse_integer_part($pattern, $format);
65
        self::parse_group_sizes($pattern, $format);
66
67
        return $format;
68
    }
69
70
    /**
71
     * @param string $pattern
72
     * @param PatternArray $format
73
     */
74
    private static function parse_multiple_patterns(string &$pattern, array &$format): void
75
    {
76
        $patterns = explode(';', $pattern);
77
78
        if (preg_match(self::PATTERN_REGEX, $patterns[0], $matches)) {
79
            $format['positive_prefix'] = $matches[1];
80
            $format['positive_suffix'] = $matches[2];
81
        }
82
83
        if (isset($patterns[1]) && preg_match(self::PATTERN_REGEX, $patterns[1], $matches)) {
84
            $format['negative_prefix'] = $matches[1];
85
            $format['negative_suffix'] = $matches[2];
86
        } else {
87
            $format['negative_prefix'] = '-' . $format['positive_prefix'];
88
            $format['negative_suffix'] = $format['positive_suffix'];
89
        }
90
91
        $pattern = $patterns[0];
92
    }
93
94
    /**
95
     * @param string $pattern
96
     * @param PatternArray $format
97
     */
98
    private static function parse_multiplier(string $pattern, array &$format): void
99
    {
100
        if (str_contains($pattern, '%')) {
101
            $format['multiplier'] = 100;
102
        } elseif (str_contains($pattern, '‰')) {
103
            $format['multiplier'] = 1000;
104
        }
105
    }
106
107
    /**
108
     * @param string $pattern
109
     * @param PatternArray $format
110
     */
111
    private static function parse_decimal_part(string &$pattern, array &$format): void
112
    {
113
        $pos = strpos($pattern, '.');
114
115
        if ($pos !== false) {
116
            $pos2 = strrpos($pattern, '0');
117
            $format['decimal_digits'] = $pos2 > $pos
118
                ? $pos2 - $pos
119
                : 0;
120
121
            $pos3 = strrpos($pattern, '#');
122
            $format['max_decimal_digits'] = $pos3 >= $pos2
123
                ? $pos3 - $pos
124
                : $format['decimal_digits'];
125
126
            $pattern = substr($pattern, 0, $pos);
127
        }
128
    }
129
130
    /**
131
     * @param string $pattern
132
     * @param PatternArray $format
133
     */
134
    private static function parse_integer_part(string $pattern, array &$format): void
135
    {
136
        $p = str_replace(',', '', $pattern);
137
        $pos = strpos($p, '0');
138
139
        $format['integer_digits'] = $pos !== false
140
            ? strrpos($p, '0') - $pos + 1
141
            : 0;
142
    }
143
144
    /**
145
     * @param string $pattern
146
     * @param PatternArray $format
147
     */
148
    private static function parse_group_sizes(string $pattern, array &$format): void
149
    {
150
        $p = str_replace('#', '0', $pattern);
151
        $pos = strrpos($pattern, ',');
152
153
        if ($pos !== false) {
154
            $pos2 = strrpos(substr($p, 0, $pos), ',');
155
            $format['group_size1'] = strrpos($p, '0') - $pos;
156
            $format['group_size2'] = $pos2 !== false ? $pos - $pos2 - 1 : 0;
157
        }
158
    }
159
}
160