diff --git a/CHANGELOG.md b/CHANGELOG.md index acc14c90ea..4f1acc6566 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Changed - Improved handling for @ in Number Format Masks [PR #3344](https://github.com/PHPOffice/PhpSpreadsheet/pull/3344) +- 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) ### Deprecated diff --git a/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php b/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php index 5250f5315a..e8b4c01cef 100644 --- a/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php +++ b/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php @@ -48,7 +48,10 @@ public static function convertToNumberIfFormatted(string &$operand): bool */ public static function convertToNumberIfNumeric(string &$operand): bool { - $value = preg_replace(['/(\d),(\d)/u', '/([+-])\s+(\d)/u'], ['$1$2', '$1$2'], trim($operand)); + $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator()); + $value = preg_replace(['/(\d)' . $thousandsSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1$2', '$1$2'], trim($operand)); + $decimalSeparator = preg_quote(StringHelper::getDecimalSeparator()); + $value = preg_replace(['/(\d)' . $decimalSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1.$2', '$1$2'], $value ?? ''); if (is_numeric($value)) { $operand = (float) $value; @@ -87,7 +90,10 @@ public static function convertToNumberIfFraction(string &$operand): bool */ public static function convertToNumberIfPercent(string &$operand): bool { - $value = preg_replace('/(\d),(\d)/u', '$1$2', $operand); + $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator()); + $value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', trim($operand)); + $decimalSeparator = preg_quote(StringHelper::getDecimalSeparator()); + $value = preg_replace(['/(\d)' . $decimalSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1.$2', '$1$2'], $value ?? ''); $match = []; 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 public static function convertToNumberIfCurrency(string &$operand): bool { $currencyRegexp = self::currencyMatcherRegexp(); - $value = preg_replace('/(\d),(\d)/u', '$1$2', $operand); + $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator()); + $value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $operand); $match = []; if ($value !== null && preg_match($currencyRegexp, $value, $match, PREG_UNMATCHED_AS_NULL)) { @@ -127,8 +134,9 @@ public static function convertToNumberIfCurrency(string &$operand): bool public static function currencyMatcherRegexp(): string { - $quotedCurrencyCode = sprintf(self::CURRENCY_CONVERSION_LIST, preg_quote(StringHelper::getCurrencyCode())); + $currencyCodes = sprintf(self::CURRENCY_CONVERSION_LIST, preg_quote(StringHelper::getCurrencyCode())); + $decimalSeparator = preg_quote(StringHelper::getDecimalSeparator()); - return '~^(?:(?: *(?[-+])? *(?[' . $quotedCurrencyCode . ']) *(?[-+])? *(?[0-9]+\.?[0-9*]*(?:E[-+]?[0-9]*)?) *)|(?: *(?[-+])? *(?[0-9]+\.?[0-9]*(?:E[-+]?[0-9]*)?) *(?[' . $quotedCurrencyCode . ']) *))$~ui'; + return '~^(?:(?: *(?[-+])? *(?[' . $currencyCodes . ']) *(?[-+])? *(?[0-9]+[' . $decimalSeparator . ']?[0-9*]*(?:E[-+]?[0-9]*)?) *)|(?: *(?[-+])? *(?[0-9]+' . $decimalSeparator . '?[0-9]*(?:E[-+]?[0-9]*)?) *(?[' . $currencyCodes . ']) *))$~ui'; } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php b/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php index 12f305b318..1525148bc6 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php @@ -177,14 +177,14 @@ public function providerPercentages(): array 'permutation_77' => ['-2.5E-8', '-%2.50E-06'], 'permutation_78' => [' - % 2.50 E -06 ', ' - % 2.50 E -06 '], 'permutation_79' => ['-2.5E-8', ' - % 2.50E-06 '], - 'permutation_80' => [' - % 2.50E- 06 ', ' - % 2.50E- 06 '], + 'permutation_80' => ['-2.5E-8', ' - % 2.50E- 06 '], 'permutation_81' => [' - % 2.50E - 06 ', ' - % 2.50E - 06 '], 'permutation_82' => ['-2.5E-6', '-2.5e-4%'], 'permutation_83' => ['200', '2e4%'], 'permutation_84' => ['-2.5E-8', '-%2.50e-06'], 'permutation_85' => [' - % 2.50 e -06 ', ' - % 2.50 e -06 '], 'permutation_86' => ['-2.5E-8', ' - % 2.50e-06 '], - 'permutation_87' => [' - % 2.50e- 06 ', ' - % 2.50e- 06 '], + 'permutation_87' => ['-2.5E-8', ' - % 2.50e- 06 '], 'permutation_88' => [' - % 2.50e - 06 ', ' - % 2.50e - 06 '], ]; }