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'], ]; } }