Skip to content

Commit

Permalink
Merge pull request #3339 from PHPOffice/Style_NumberFormat-New-Fractions
Browse files Browse the repository at this point in the history
Support for fixed value divisor in fractional Number Format Masks
  • Loading branch information
MarkBaker authored Feb 2, 2023
2 parents 3f8b39c + c47af2a commit e573b45
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 72 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Added

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

### Changed

Expand Down
23 changes: 14 additions & 9 deletions src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,28 @@ public static function format($value, string $format): string
$decimalLength = strlen($decimalPart);
$decimalDivisor = 10 ** $decimalLength;

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

$adjustedDecimalPart = $decimalPartx / $GCD;
$adjustedDecimalDivisor = $decimalDivisor / $GCD;
if (is_numeric($matches[2])) {
$fractionDivisor = 100 / (int) $matches[2];
} else {
/** @var float */
$fractionDivisor = MathTrig\Gcd::evaluate((int) $decimalPart, $decimalDivisor);
}

$adjustedDecimalPart = (int) round((int) $decimalPart / $fractionDivisor, 0);
$adjustedDecimalDivisor = $decimalDivisor / $fractionDivisor;

if ((strpos($format, '0') !== false)) {
if ((strpos($formatIntegerPart, '0') !== false)) {
return "{$sign}{$integerPart} {$adjustedDecimalPart}/{$adjustedDecimalDivisor}";
} elseif ((strpos($format, '#') !== false)) {
} elseif ((strpos($formatIntegerPart, '#') !== false)) {
if ($integerPart == 0) {
return "{$sign}{$adjustedDecimalPart}/{$adjustedDecimalDivisor}";
}

return "{$sign}{$integerPart} {$adjustedDecimalPart}/{$adjustedDecimalDivisor}";
} elseif ((substr($format, 0, 3) == '? ?')) {
} elseif ((substr($formatIntegerPart, 0, 3) == '? ?')) {
if ($integerPart == 0) {
$integerPart = '';
}
Expand Down
2 changes: 1 addition & 1 deletion src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ public static function format($value, string $format): string
$format = self::pregReplace('/0,+/', '0', $format);
$format = self::pregReplace('/#,+/', '#', $format);
}
if (preg_match('/#?.*\?\/\?/', $format, $m)) {
if (preg_match('/#?.*\?\/(\?+|\d+)/', $format)) {
$value = FractionFormatter::format($value, $format);
} else {
// Handle the number itself
Expand Down
17 changes: 17 additions & 0 deletions tests/PhpSpreadsheetTests/Style/NumberFormatTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ public function providerNumberFormat(): array
return require 'tests/data/Style/NumberFormat.php';
}

/**
* @dataProvider providerNumberFormatFractions
*
* @param mixed $expectedResult
* @param mixed $args
*/
public function testFormatValueWithMaskFraction($expectedResult, ...$args): void
{
$result = NumberFormat::toFormattedString(...$args);
self::assertEquals($expectedResult, $result);
}

public function providerNumberFormatFractions(): array
{
return require 'tests/data/Style/NumberFormatFractions.php';
}

/**
* @dataProvider providerNumberFormatDates
*
Expand Down
62 changes: 0 additions & 62 deletions tests/data/Style/NumberFormat.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,68 +267,6 @@
-0.123,
'_(0.00%_;( 0.00% )',
],
// Fraction
[
'5 1/4',
5.25,
'# ???/???',
],
// Vulgar Fraction
[
'5 3/10',
5.2999999999999998,
'# ???/???',
],
[
'21/4',
5.25,
'???/???',
],
[
'0 3/4',
0.75,
'0??/???',
],
[
'3/4',
0.75,
'#??/???',
],
[
' 3/4',
0.75,
'? ??/???',
],
[
' 3/4',
'0.75000',
'? ??/???',
],
[
'5 1/16',
5.0625,
'? ??/???',
],
[
'- 5/8',
-0.625,
'? ??/???',
],
[
'0',
0,
'? ??/???',
],
[
'0',
'0.000',
'? ??/???',
],
[
'-16',
'-016.0',
'? ??/???',
],
// Complex formats
[
'(001) 2-3456-789',
Expand Down
104 changes: 104 additions & 0 deletions tests/data/Style/NumberFormatFractions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

// value, format, result

return [
// Fraction
[
'5 1/4',
5.25,
'# ???/???',
],
[
'5 3/10',
5.2999999999999998,
'# ???/???',
],
// Vulgar Fraction
[
'21/4',
5.25,
'???/???',
],
[
'0 3/4',
0.75,
'0??/???',
],
[
'3/4',
0.75,
'#??/???',
],
[
' 3/4',
0.75,
'? ??/???',
],
[
' 3/4',
'0.75000',
'? ??/???',
],
[
'5 1/16',
5.0625,
'? ??/???',
],
[
'- 5/8',
-0.625,
'? ??/???',
],
[
'0',
0,
'? ??/???',
],
[
'0',
'0.000',
'? ??/???',
],
[
'-16',
'-016.0',
'? ??/???',
],
// Fixed base Fraction
[
'5 1/2',
5.25,
'# ???/2',
],
[
'5 1/4',
5.25,
'# ???/4',
],
[
'5 2/8',
5.25,
'# ???/8',
],
[
'5 3/10',
5.25,
'# ???/10',
],
[
'5 25/100',
5.25,
'# ???/100',
],
[
'525/100',
5.25,
'??/100',
],
[
'525/100',
5.25,
'???/100',
],
];

0 comments on commit e573b45

Please sign in to comment.