Skip to content

Commit c47af2a

Browse files
committed
Support for fixed value divisor in fractional Number Format Masks
1 parent 3f8b39c commit c47af2a

File tree

6 files changed

+137
-72
lines changed

6 files changed

+137
-72
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
1010
### Added
1111

1212
- Support for configuring a Chart Title's overlay [PR #3325](https://github.com/PHPOffice/PhpSpreadsheet/pull/3325)
13+
- Support for fixed value divisor in fractional Number Format Masks [PR #3339](https://github.com/PHPOffice/PhpSpreadsheet/pull/3339)
1314

1415
### Changed
1516

src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,28 @@ public static function format($value, string $format): string
2626
$decimalLength = strlen($decimalPart);
2727
$decimalDivisor = 10 ** $decimalLength;
2828

29-
/** @var float */
30-
$GCD = MathTrig\Gcd::evaluate($decimalPart, $decimalDivisor);
31-
/** @var float */
32-
$decimalPartx = $decimalPart;
29+
preg_match('/(#?.*\?)\/(\?+|\d+)/', $format, $matches);
30+
$formatIntegerPart = $matches[1];
3331

34-
$adjustedDecimalPart = $decimalPartx / $GCD;
35-
$adjustedDecimalDivisor = $decimalDivisor / $GCD;
32+
if (is_numeric($matches[2])) {
33+
$fractionDivisor = 100 / (int) $matches[2];
34+
} else {
35+
/** @var float */
36+
$fractionDivisor = MathTrig\Gcd::evaluate((int) $decimalPart, $decimalDivisor);
37+
}
38+
39+
$adjustedDecimalPart = (int) round((int) $decimalPart / $fractionDivisor, 0);
40+
$adjustedDecimalDivisor = $decimalDivisor / $fractionDivisor;
3641

37-
if ((strpos($format, '0') !== false)) {
42+
if ((strpos($formatIntegerPart, '0') !== false)) {
3843
return "{$sign}{$integerPart} {$adjustedDecimalPart}/{$adjustedDecimalDivisor}";
39-
} elseif ((strpos($format, '#') !== false)) {
44+
} elseif ((strpos($formatIntegerPart, '#') !== false)) {
4045
if ($integerPart == 0) {
4146
return "{$sign}{$adjustedDecimalPart}/{$adjustedDecimalDivisor}";
4247
}
4348

4449
return "{$sign}{$integerPart} {$adjustedDecimalPart}/{$adjustedDecimalDivisor}";
45-
} elseif ((substr($format, 0, 3) == '? ?')) {
50+
} elseif ((substr($formatIntegerPart, 0, 3) == '? ?')) {
4651
if ($integerPart == 0) {
4752
$integerPart = '';
4853
}

src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public static function format($value, string $format): string
226226
$format = self::pregReplace('/0,+/', '0', $format);
227227
$format = self::pregReplace('/#,+/', '#', $format);
228228
}
229-
if (preg_match('/#?.*\?\/\?/', $format, $m)) {
229+
if (preg_match('/#?.*\?\/(\?+|\d+)/', $format)) {
230230
$value = FractionFormatter::format($value, $format);
231231
} else {
232232
// Handle the number itself

tests/PhpSpreadsheetTests/Style/NumberFormatTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,23 @@ public function providerNumberFormat(): array
5656
return require 'tests/data/Style/NumberFormat.php';
5757
}
5858

59+
/**
60+
* @dataProvider providerNumberFormatFractions
61+
*
62+
* @param mixed $expectedResult
63+
* @param mixed $args
64+
*/
65+
public function testFormatValueWithMaskFraction($expectedResult, ...$args): void
66+
{
67+
$result = NumberFormat::toFormattedString(...$args);
68+
self::assertEquals($expectedResult, $result);
69+
}
70+
71+
public function providerNumberFormatFractions(): array
72+
{
73+
return require 'tests/data/Style/NumberFormatFractions.php';
74+
}
75+
5976
/**
6077
* @dataProvider providerNumberFormatDates
6178
*

tests/data/Style/NumberFormat.php

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -267,68 +267,6 @@
267267
-0.123,
268268
'_(0.00%_;( 0.00% )',
269269
],
270-
// Fraction
271-
[
272-
'5 1/4',
273-
5.25,
274-
'# ???/???',
275-
],
276-
// Vulgar Fraction
277-
[
278-
'5 3/10',
279-
5.2999999999999998,
280-
'# ???/???',
281-
],
282-
[
283-
'21/4',
284-
5.25,
285-
'???/???',
286-
],
287-
[
288-
'0 3/4',
289-
0.75,
290-
'0??/???',
291-
],
292-
[
293-
'3/4',
294-
0.75,
295-
'#??/???',
296-
],
297-
[
298-
' 3/4',
299-
0.75,
300-
'? ??/???',
301-
],
302-
[
303-
' 3/4',
304-
'0.75000',
305-
'? ??/???',
306-
],
307-
[
308-
'5 1/16',
309-
5.0625,
310-
'? ??/???',
311-
],
312-
[
313-
'- 5/8',
314-
-0.625,
315-
'? ??/???',
316-
],
317-
[
318-
'0',
319-
0,
320-
'? ??/???',
321-
],
322-
[
323-
'0',
324-
'0.000',
325-
'? ??/???',
326-
],
327-
[
328-
'-16',
329-
'-016.0',
330-
'? ??/???',
331-
],
332270
// Complex formats
333271
[
334272
'(001) 2-3456-789',
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
// value, format, result
4+
5+
return [
6+
// Fraction
7+
[
8+
'5 1/4',
9+
5.25,
10+
'# ???/???',
11+
],
12+
[
13+
'5 3/10',
14+
5.2999999999999998,
15+
'# ???/???',
16+
],
17+
// Vulgar Fraction
18+
[
19+
'21/4',
20+
5.25,
21+
'???/???',
22+
],
23+
[
24+
'0 3/4',
25+
0.75,
26+
'0??/???',
27+
],
28+
[
29+
'3/4',
30+
0.75,
31+
'#??/???',
32+
],
33+
[
34+
' 3/4',
35+
0.75,
36+
'? ??/???',
37+
],
38+
[
39+
' 3/4',
40+
'0.75000',
41+
'? ??/???',
42+
],
43+
[
44+
'5 1/16',
45+
5.0625,
46+
'? ??/???',
47+
],
48+
[
49+
'- 5/8',
50+
-0.625,
51+
'? ??/???',
52+
],
53+
[
54+
'0',
55+
0,
56+
'? ??/???',
57+
],
58+
[
59+
'0',
60+
'0.000',
61+
'? ??/???',
62+
],
63+
[
64+
'-16',
65+
'-016.0',
66+
'? ??/???',
67+
],
68+
// Fixed base Fraction
69+
[
70+
'5 1/2',
71+
5.25,
72+
'# ???/2',
73+
],
74+
[
75+
'5 1/4',
76+
5.25,
77+
'# ???/4',
78+
],
79+
[
80+
'5 2/8',
81+
5.25,
82+
'# ???/8',
83+
],
84+
[
85+
'5 3/10',
86+
5.25,
87+
'# ???/10',
88+
],
89+
[
90+
'5 25/100',
91+
5.25,
92+
'# ???/100',
93+
],
94+
[
95+
'525/100',
96+
5.25,
97+
'??/100',
98+
],
99+
[
100+
'525/100',
101+
5.25,
102+
'???/100',
103+
],
104+
];

0 commit comments

Comments
 (0)