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.
This commit is contained in:
parent
d88af46ab5
commit
d0dd5b4594
|
|
@ -755,16 +755,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\WildcardMatch\\:\\:wildcard\\(\\) should return string but returns string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\WildcardMatch\\:\\:compare\\(\\) has parameter \\$value with no typehint specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php
|
||||
|
||||
-
|
||||
message: "#^Call to function is_string\\(\\) with null will always evaluate to false\\.$#"
|
||||
count: 3
|
||||
|
|
|
|||
|
|
@ -5,30 +5,30 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Internal;
|
|||
class WildcardMatch
|
||||
{
|
||||
private const SEARCH_SET = [
|
||||
'/(?<!~)\*/ui',
|
||||
'/~\*/ui',
|
||||
'/(?<!~)\?/ui',
|
||||
'/~\?/ui',
|
||||
'~~', // convert double tilde to unprintable value
|
||||
'~\\*', // convert tilde backslash asterisk to [*] (matches literal asterisk in regexp)
|
||||
'\\*', // convert backslash asterisk to .* (matches string of any length in regexp)
|
||||
'~\\?', // convert tilde backslash question to [?] (matches literal question mark in regexp)
|
||||
'\\?', // convert backslash question to . (matches one character in regexp)
|
||||
"\x1c", // convert original double tilde to single tilde
|
||||
];
|
||||
|
||||
private const REPLACEMENT_SET = [
|
||||
'${1}.*',
|
||||
'\*',
|
||||
'${1}.',
|
||||
'\?',
|
||||
"\x1c",
|
||||
'[*]',
|
||||
'.*',
|
||||
'[?]',
|
||||
'.',
|
||||
'~',
|
||||
];
|
||||
|
||||
public static function wildcard(string $wildcard): string
|
||||
{
|
||||
// Preg Escape the wildcard, but protecting the Excel * and ? search characters
|
||||
$wildcard = str_replace(['*', '?'], [0x1A, 0x1B], $wildcard);
|
||||
$wildcard = preg_quote($wildcard);
|
||||
$wildcard = str_replace([0x1A, 0x1B], ['*', '?'], $wildcard);
|
||||
|
||||
return preg_replace(self::SEARCH_SET, self::REPLACEMENT_SET, $wildcard);
|
||||
return str_replace(self::SEARCH_SET, self::REPLACEMENT_SET, preg_quote($wildcard));
|
||||
}
|
||||
|
||||
public static function compare($value, string $wildcard): bool
|
||||
public static function compare(string $value, string $wildcard): bool
|
||||
{
|
||||
if ($value === '') {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use DateTime;
|
|||
use DateTimeZone;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Internal\WildcardMatch;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\Date;
|
||||
|
|
@ -452,13 +453,6 @@ class AutoFilter
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search/Replace arrays to convert Excel wildcard syntax to a regexp syntax for preg_matching.
|
||||
*/
|
||||
private const FROM_REPLACE = ['~~', '~\\*', '\\*', '~\\?', '\\?', "\x1c"];
|
||||
|
||||
private const TO_REPLACE = ["\x1c", '[*]', '.*', '[?]', '.', '~'];
|
||||
|
||||
private static function makeDateObject(int $year, int $month, int $day, int $hour = 0, int $minute = 0, int $second = 0): DateTime
|
||||
{
|
||||
$baseDate = new DateTime();
|
||||
|
|
@ -853,8 +847,7 @@ class AutoFilter
|
|||
$ruleValue = $rule->getValue();
|
||||
if (!is_array($ruleValue) && !is_numeric($ruleValue)) {
|
||||
// Convert to a regexp allowing for regexp reserved characters, wildcards and escaped wildcards
|
||||
$ruleValue = preg_quote("$ruleValue");
|
||||
$ruleValue = str_replace(self::FROM_REPLACE, self::TO_REPLACE, $ruleValue);
|
||||
$ruleValue = WildcardMatch::wildcard($ruleValue);
|
||||
if (trim($ruleValue) == '') {
|
||||
$customRuleForBlanks = true;
|
||||
$ruleValue = trim($ruleValue);
|
||||
|
|
|
|||
|
|
@ -346,4 +346,10 @@ return [
|
|||
['Obtuse', 'Amuse', 'Obverse', 'Inverse', 'Assurance', 'Amplitude', 'Adverse', 'Apartment'],
|
||||
0,
|
||||
],
|
||||
[
|
||||
3, // Expected
|
||||
'*~~*', // contains a tilde
|
||||
['aAAAAA', 'a123456*c', 'abc~xyz', 'alembic'],
|
||||
0,
|
||||
],
|
||||
];
|
||||
|
|
|
|||
Loading…
Reference in New Issue