From 4aaf1f61b9228b3d3af88c86e325fdf26812ff93 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Fri, 17 Feb 2023 06:15:08 +0100 Subject: [PATCH] Allow a range of different potential currency codes (including the locale code) in the currency matcher regexp (dollar, euro, pound sterling and yen) --- .../Calculation/Engine/FormattedNumber.php | 16 ++++++++++++---- .../Calculation/Engine/FormattedNumberTest.php | 5 +++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php b/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php index 8fe7aa446e..5250f5315a 100644 --- a/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php +++ b/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php @@ -13,6 +13,9 @@ class FormattedNumber private const STRING_REGEXP_PERCENT = '~^(?:(?: *(?[-+])? *\% *(?[-+])? *(?[0-9]+\.?[0-9*]*(?:E[-+]?[0-9]*)?) *)|(?: *(?[-+])? *(?[0-9]+\.?[0-9]*(?:E[-+]?[0-9]*)?) *\% *))$~i'; + // preg_quoted string for major currency symbols, with a %s for locale currency + private const CURRENCY_CONVERSION_LIST = '\$€£¥%s'; + private const STRING_CONVERSION_LIST = [ [self::class, 'convertToNumberIfNumeric'], [self::class, 'convertToNumberIfFraction'], @@ -106,13 +109,11 @@ public static function convertToNumberIfPercent(string &$operand): bool */ public static function convertToNumberIfCurrency(string &$operand): bool { - $quotedCurrencyCode = preg_quote(StringHelper::getCurrencyCode()); - + $currencyRegexp = self::currencyMatcherRegexp(); $value = preg_replace('/(\d),(\d)/u', '$1$2', $operand); - $regExp = '~^(?:(?: *(?[-+])? *' . $quotedCurrencyCode . ' *(?[-+])? *(?[0-9]+\.?[0-9*]*(?:E[-+]?[0-9]*)?) *)|(?: *(?[-+])? *(?[0-9]+\.?[0-9]*(?:E[-+]?[0-9]*)?) *' . $quotedCurrencyCode . ' *))$~ui'; $match = []; - if ($value !== null && preg_match($regExp, $value, $match, PREG_UNMATCHED_AS_NULL)) { + if ($value !== null && preg_match($currencyRegexp, $value, $match, PREG_UNMATCHED_AS_NULL)) { //Determine the sign $sign = ($match['PrefixedSign'] ?? $match['PrefixedSign2'] ?? $match['PostfixedSign']) ?? ''; //Cast to a float @@ -123,4 +124,11 @@ public static function convertToNumberIfCurrency(string &$operand): bool return false; } + + public static function currencyMatcherRegexp(): string + { + $quotedCurrencyCode = sprintf(self::CURRENCY_CONVERSION_LIST, preg_quote(StringHelper::getCurrencyCode())); + + return '~^(?:(?: *(?[-+])? *(?[' . $quotedCurrencyCode . ']) *(?[-+])? *(?[0-9]+\.?[0-9*]*(?:E[-+]?[0-9]*)?) *)|(?: *(?[-+])? *(?[0-9]+\.?[0-9]*(?:E[-+]?[0-9]*)?) *(?[' . $quotedCurrencyCode . ']) *))$~ui'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php b/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php index ee71dc495b..12f305b318 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Engine/FormattedNumberTest.php @@ -233,6 +233,11 @@ public function providerCurrencies(): array 'basic_postfix_scientific_currency_with_spaces' => ['2000000', "2E6 {$currencyCode}"], 'high_value_currency_with_thousands_separator' => ['2750000', "+{$currencyCode} 2,750,000"], + + 'explicit dollar' => ['2.75', '$2.75'], + 'explicit euro' => ['2.75', '2.75€'], + 'explicit pound sterling' => ['2.75', '£2.75'], + 'explicit yen' => ['275', '¥275'], ]; } }