Skip to content

Commit d49bc40

Browse files
authored
Merge pull request #3374 from PHPOffice/CalcEngine_Formatted-Number-Localisation
Improve support for locale settings in the Calculation Engine formatted number matcher
2 parents d029042 + 3d7964f commit d49bc40

File tree

3 files changed

+16
-7
lines changed

3 files changed

+16
-7
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
1818
### Changed
1919

2020
- Improved handling for @ in Number Format Masks [PR #3344](https://github.com/PHPOffice/PhpSpreadsheet/pull/3344)
21+
- Improved support for locale settings and currency codes when matching formatted strings to numerics in the Calculation Engine [PR #3373](https://github.com/PHPOffice/PhpSpreadsheet/pull/3373) and [PR #3374](https://github.com/PHPOffice/PhpSpreadsheet/pull/3374)
2122

2223
### Deprecated
2324

src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php

+13-5
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ public static function convertToNumberIfFormatted(string &$operand): bool
4848
*/
4949
public static function convertToNumberIfNumeric(string &$operand): bool
5050
{
51-
$value = preg_replace(['/(\d),(\d)/u', '/([+-])\s+(\d)/u'], ['$1$2', '$1$2'], trim($operand));
51+
$thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator());
52+
$value = preg_replace(['/(\d)' . $thousandsSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1$2', '$1$2'], trim($operand));
53+
$decimalSeparator = preg_quote(StringHelper::getDecimalSeparator());
54+
$value = preg_replace(['/(\d)' . $decimalSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1.$2', '$1$2'], $value ?? '');
5255

5356
if (is_numeric($value)) {
5457
$operand = (float) $value;
@@ -87,7 +90,10 @@ public static function convertToNumberIfFraction(string &$operand): bool
8790
*/
8891
public static function convertToNumberIfPercent(string &$operand): bool
8992
{
90-
$value = preg_replace('/(\d),(\d)/u', '$1$2', $operand);
93+
$thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator());
94+
$value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', trim($operand));
95+
$decimalSeparator = preg_quote(StringHelper::getDecimalSeparator());
96+
$value = preg_replace(['/(\d)' . $decimalSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1.$2', '$1$2'], $value ?? '');
9197

9298
$match = [];
9399
if ($value !== null && preg_match(self::STRING_REGEXP_PERCENT, $value, $match, PREG_UNMATCHED_AS_NULL)) {
@@ -110,7 +116,8 @@ public static function convertToNumberIfPercent(string &$operand): bool
110116
public static function convertToNumberIfCurrency(string &$operand): bool
111117
{
112118
$currencyRegexp = self::currencyMatcherRegexp();
113-
$value = preg_replace('/(\d),(\d)/u', '$1$2', $operand);
119+
$thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator());
120+
$value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $operand);
114121

115122
$match = [];
116123
if ($value !== null && preg_match($currencyRegexp, $value, $match, PREG_UNMATCHED_AS_NULL)) {
@@ -127,8 +134,9 @@ public static function convertToNumberIfCurrency(string &$operand): bool
127134

128135
public static function currencyMatcherRegexp(): string
129136
{
130-
$quotedCurrencyCode = sprintf(self::CURRENCY_CONVERSION_LIST, preg_quote(StringHelper::getCurrencyCode()));
137+
$currencyCodes = sprintf(self::CURRENCY_CONVERSION_LIST, preg_quote(StringHelper::getCurrencyCode()));
138+
$decimalSeparator = preg_quote(StringHelper::getDecimalSeparator());
131139

132-
return '~^(?:(?: *(?<PrefixedSign>[-+])? *(?<PrefixedCurrency>[' . $quotedCurrencyCode . ']) *(?<PrefixedSign2>[-+])? *(?<PrefixedValue>[0-9]+\.?[0-9*]*(?:E[-+]?[0-9]*)?) *)|(?: *(?<PostfixedSign>[-+])? *(?<PostfixedValue>[0-9]+\.?[0-9]*(?:E[-+]?[0-9]*)?) *(?<PostCurrency>[' . $quotedCurrencyCode . ']) *))$~ui';
140+
return '~^(?:(?: *(?<PrefixedSign>[-+])? *(?<PrefixedCurrency>[' . $currencyCodes . ']) *(?<PrefixedSign2>[-+])? *(?<PrefixedValue>[0-9]+[' . $decimalSeparator . ']?[0-9*]*(?:E[-+]?[0-9]*)?) *)|(?: *(?<PostfixedSign>[-+])? *(?<PostfixedValue>[0-9]+' . $decimalSeparator . '?[0-9]*(?:E[-+]?[0-9]*)?) *(?<PostCurrency>[' . $currencyCodes . ']) *))$~ui';
133141
}
134142
}

tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,14 @@ public function providerPercentages(): array
177177
'permutation_77' => ['-2.5E-8', '-%2.50E-06'],
178178
'permutation_78' => [' - % 2.50 E -06 ', ' - % 2.50 E -06 '],
179179
'permutation_79' => ['-2.5E-8', ' - % 2.50E-06 '],
180-
'permutation_80' => [' - % 2.50E- 06 ', ' - % 2.50E- 06 '],
180+
'permutation_80' => ['-2.5E-8', ' - % 2.50E- 06 '],
181181
'permutation_81' => [' - % 2.50E - 06 ', ' - % 2.50E - 06 '],
182182
'permutation_82' => ['-2.5E-6', '-2.5e-4%'],
183183
'permutation_83' => ['200', '2e4%'],
184184
'permutation_84' => ['-2.5E-8', '-%2.50e-06'],
185185
'permutation_85' => [' - % 2.50 e -06 ', ' - % 2.50 e -06 '],
186186
'permutation_86' => ['-2.5E-8', ' - % 2.50e-06 '],
187-
'permutation_87' => [' - % 2.50e- 06 ', ' - % 2.50e- 06 '],
187+
'permutation_87' => ['-2.5E-8', ' - % 2.50e- 06 '],
188188
'permutation_88' => [' - % 2.50e - 06 ', ' - % 2.50e - 06 '],
189189
];
190190
}

0 commit comments

Comments
 (0)