From 4b568b47b420253228ec2426f72ccc8adb1cfbce Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:20:32 -0800 Subject: [PATCH] Handle Case Where Both Format and Value Contain Quotation Mark --- .../Style/NumberFormat/Formatter.php | 15 ++++++++-- tests/data/Style/NumberFormat.php | 28 ++++++++++++++++--- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php b/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php index 886cb688ef..7a6b38f376 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php +++ b/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php @@ -14,6 +14,7 @@ class Formatter extends BaseFormatter * Matches any @ symbol that isn't enclosed in quotes. */ private const SYMBOL_AT = '/@(?=(?:[^"]*"[^"]*")*[^"]*\Z)/miu'; + private const QUOTE_REPLACEMENT = "\u{fffe}"; // invalid Unicode character /** * Matches any ; symbol that isn't enclosed in quotes, for a "section" split. @@ -130,9 +131,17 @@ public static function toFormattedString($value, string $format, ?array $callBac return str_replace('@', $value, $format); } //escape any dollar signs on the string, so they are not replaced with an empty value - $value = str_replace('$', '\\$', (string) $value); - - return str_replace('"', '', preg_replace(self::SYMBOL_AT, $value, $format) ?? $value); + $value = str_replace( + ['$', '"'], + ['\\$', self::QUOTE_REPLACEMENT], + (string) $value + ); + + return str_replace( + ['"', self::QUOTE_REPLACEMENT], + ['', '"'], + preg_replace(self::SYMBOL_AT, $value, $format) ?? $value + ); } // If we have a text value, return it "as is" diff --git a/tests/data/Style/NumberFormat.php b/tests/data/Style/NumberFormat.php index 374390e749..da06d7a368 100644 --- a/tests/data/Style/NumberFormat.php +++ b/tests/data/Style/NumberFormat.php @@ -1682,24 +1682,44 @@ '#,##0.00;;"---"', ], 'issue 4124' => ['1 HUF', 1, '#,##0_-[$HUF]'], - 'issue 4242-0' => [ + 'issue 4242 General with dollar sign' => [ 'General $200 - 200', // expected result 'General $200 - 200', // cell contents NumberFormat::FORMAT_GENERAL, // cell style ], - 'issue 4242-1' => [ + 'issue 4242 Text with dollar sign' => [ 'Text $200 - 200', 'Text $200 - 200', NumberFormat::FORMAT_TEXT, ], - 'issue 4242-2' => [ + 'issue 4242 Text with quotes, format without' => [ '"Hello" she said and "Hello" I replied', '"Hello" she said and "Hello" I replied', NumberFormat::FORMAT_TEXT, ], - 'issue 4242-3' => [ + 'issue 4242 Format with quotes, text without' => [ 'Text: $200 - 200', '$200 - 200', '"Text: "' . NumberFormat::FORMAT_TEXT, ], + 'issue 4242 single quote mark' => [ + '"', + '"', + '@', + ], + 'issue 4242 dollar sign' => [ + '$100', + '$100', + '@', + ], + 'issue 4242 repeat unquoted at signs' => [ + 'xy xy xy', + 'xy', + '@ @ @', + ], + 'issue 4242 quotes in format and text' => [ + 'Text: "Hooray" for me', + '"Hooray" for me', + '"Text: "' . NumberFormat::FORMAT_TEXT, + ], ];