Skip to content

Commit d0dd5b4

Browse files
oleibmanMarkBaker
authored andcommitted
Use WildcardMatch
Per suggestion from @MarkBaker. WildcardMatch did not handle double tilde correctly. It has been changed to do so and its logic simplified (and commented). Existing AutoFilter test covered this situation, but I added a test for MATCH as well.
1 parent d88af46 commit d0dd5b4

File tree

4 files changed

+22
-33
lines changed

4 files changed

+22
-33
lines changed

phpstan-baseline.neon

-10
Original file line numberDiff line numberDiff line change
@@ -755,16 +755,6 @@ parameters:
755755
count: 1
756756
path: src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php
757757

758-
-
759-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\WildcardMatch\\:\\:wildcard\\(\\) should return string but returns string\\|null\\.$#"
760-
count: 1
761-
path: src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php
762-
763-
-
764-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\WildcardMatch\\:\\:compare\\(\\) has parameter \\$value with no typehint specified\\.$#"
765-
count: 1
766-
path: src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php
767-
768758
-
769759
message: "#^Call to function is_string\\(\\) with null will always evaluate to false\\.$#"
770760
count: 3

src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php

+14-14
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,30 @@
55
class WildcardMatch
66
{
77
private const SEARCH_SET = [
8-
'/(?<!~)\*/ui',
9-
'/~\*/ui',
10-
'/(?<!~)\?/ui',
11-
'/~\?/ui',
8+
'~~', // convert double tilde to unprintable value
9+
'~\\*', // convert tilde backslash asterisk to [*] (matches literal asterisk in regexp)
10+
'\\*', // convert backslash asterisk to .* (matches string of any length in regexp)
11+
'~\\?', // convert tilde backslash question to [?] (matches literal question mark in regexp)
12+
'\\?', // convert backslash question to . (matches one character in regexp)
13+
"\x1c", // convert original double tilde to single tilde
1214
];
1315

1416
private const REPLACEMENT_SET = [
15-
'${1}.*',
16-
'\*',
17-
'${1}.',
18-
'\?',
17+
"\x1c",
18+
'[*]',
19+
'.*',
20+
'[?]',
21+
'.',
22+
'~',
1923
];
2024

2125
public static function wildcard(string $wildcard): string
2226
{
2327
// Preg Escape the wildcard, but protecting the Excel * and ? search characters
24-
$wildcard = str_replace(['*', '?'], [0x1A, 0x1B], $wildcard);
25-
$wildcard = preg_quote($wildcard);
26-
$wildcard = str_replace([0x1A, 0x1B], ['*', '?'], $wildcard);
27-
28-
return preg_replace(self::SEARCH_SET, self::REPLACEMENT_SET, $wildcard);
28+
return str_replace(self::SEARCH_SET, self::REPLACEMENT_SET, preg_quote($wildcard));
2929
}
3030

31-
public static function compare($value, string $wildcard): bool
31+
public static function compare(string $value, string $wildcard): bool
3232
{
3333
if ($value === '') {
3434
return true;

src/PhpSpreadsheet/Worksheet/AutoFilter.php

+2-9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use DateTimeZone;
77
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
88
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
9+
use PhpOffice\PhpSpreadsheet\Calculation\Internal\WildcardMatch;
910
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
1011
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
1112
use PhpOffice\PhpSpreadsheet\Shared\Date;
@@ -452,13 +453,6 @@ private static function filterTestInPeriodDateSet($cellValue, $monthSet)
452453
return false;
453454
}
454455

455-
/**
456-
* Search/Replace arrays to convert Excel wildcard syntax to a regexp syntax for preg_matching.
457-
*/
458-
private const FROM_REPLACE = ['~~', '~\\*', '\\*', '~\\?', '\\?', "\x1c"];
459-
460-
private const TO_REPLACE = ["\x1c", '[*]', '.*', '[?]', '.', '~'];
461-
462456
private static function makeDateObject(int $year, int $month, int $day, int $hour = 0, int $minute = 0, int $second = 0): DateTime
463457
{
464458
$baseDate = new DateTime();
@@ -853,8 +847,7 @@ public function showHideRows()
853847
$ruleValue = $rule->getValue();
854848
if (!is_array($ruleValue) && !is_numeric($ruleValue)) {
855849
// Convert to a regexp allowing for regexp reserved characters, wildcards and escaped wildcards
856-
$ruleValue = preg_quote("$ruleValue");
857-
$ruleValue = str_replace(self::FROM_REPLACE, self::TO_REPLACE, $ruleValue);
850+
$ruleValue = WildcardMatch::wildcard($ruleValue);
858851
if (trim($ruleValue) == '') {
859852
$customRuleForBlanks = true;
860853
$ruleValue = trim($ruleValue);

tests/data/Calculation/LookupRef/MATCH.php

+6
Original file line numberDiff line numberDiff line change
@@ -346,4 +346,10 @@
346346
['Obtuse', 'Amuse', 'Obverse', 'Inverse', 'Assurance', 'Amplitude', 'Adverse', 'Apartment'],
347347
0,
348348
],
349+
[
350+
3, // Expected
351+
'*~~*', // contains a tilde
352+
['aAAAAA', 'a123456*c', 'abc~xyz', 'alembic'],
353+
0,
354+
],
349355
];

0 commit comments

Comments
 (0)