Passed
Push — master ( 3d00c9...7a9fdc )
by Alexander
02:06
created

WildcardPattern::withEnding()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Strings;
6
7
/**
8
 * A wildcard pattern to match strings against.
9
 *
10
 * - `\` escapes other special characters if usage of escape character is not turned off.
11
 * - `*` matches any string including the empty string except it has a delimiter (`/` and `\` by default).
12
  * - `**` matches any string including the empty string and delimiters.
13
 * - `?` matches any single character.
14
 * - `[seq]` matches any character in seq.
15
 * - `[a-z]` matches any character from a to z.
16
 * - `[!seq]` matches any character not in seq.
17
 * - `[[:alnum:]]` matches POSIX style character classes,
18
 *   see {@see https://www.php.net/manual/en/regexp.reference.character-classes.php}.
19
 */
20
final class WildcardPattern
21
{
22
    private bool $ignoreCase = false;
23
    private string $pattern;
24
    private array $delimiters;
25
26
    /**
27
     * @param string $pattern The shell wildcard pattern to match against.
28
     * @param array $delimiters Delimiters to consider for "*" (`/` and `\` by default).
29
     */
30 59
    public function __construct(string $pattern, array $delimiters = ['\\\\', '/'])
31
    {
32 59
        $this->pattern = $pattern;
33 59
        $this->delimiters = $delimiters;
34 59
    }
35
36
    /**
37
     * Checks if the passed string would match the given shell wildcard pattern.
38
     *
39
     * @param string $string The tested string.
40
     *
41
     * @return bool Whether the string matches pattern or not.
42
     */
43 58
    public function match(string $string): bool
44
    {
45 58
        if ($this->pattern === '**') {
46 1
            return true;
47
        }
48
49 57
        $pattern = $this->pattern;
50
51
        $replacements = [
52 57
            '\*\*' => '.*',
53
            '\\\\\\\\' => '\\\\',
54
            '\\\\\\*' => '[*]',
55
            '\\\\\\?' => '[?]',
56
            '\\\\\\[' => '[\[]',
57
            '\\\\\\]' => '[\]]',
58
        ];
59
60 57
        if ($this->delimiters === []) {
61
            $replacements += [
62 1
                '\*' => '.*',
63
                '\?' => '?',
64
            ];
65
        } else {
66 56
            $notDelimiters = '[^' . preg_quote(implode('', $this->delimiters), '#') . ']';
67
            $replacements += [
68 56
                '\*' => "$notDelimiters*",
69 56
                '\?' => $notDelimiters,
70
            ];
71
        }
72
73
        $replacements += [
74 57
            '\[\!' => '[^',
75
            '\[' => '[',
76
            '\]' => ']',
77
            '\-' => '-',
78
        ];
79
80 57
        $pattern = strtr(preg_quote($pattern, '#'), $replacements);
81 57
        $pattern = '#^' . $pattern . '$#us';
82
83 57
        if ($this->ignoreCase) {
84 1
            $pattern .= 'i';
85
        }
86
87 57
        return preg_match($pattern, $string) === 1;
88
    }
89
90
    /**
91
     * Make pattern case insensitive.
92
     *
93
     * @param bool $flag
94
     *
95
     * @return self
96
     */
97 3
    public function ignoreCase(bool $flag = true): self
98
    {
99 3
        $new = clone $this;
100 3
        $new->ignoreCase = $flag;
101 3
        return $new;
102
    }
103
104
    /**
105
     * Returns whether the pattern contains a dynamic part i.e.
106
     * has unescaped "*",  "{", "?", or "[" character.
107
     *
108
     * @param string $pattern The pattern to check.
109
     *
110
     * @return bool Whether the pattern contains a dynamic part.
111
     */
112 5
    public static function isDynamic(string $pattern): bool
113
    {
114 5
        $pattern = preg_replace('/\\\\./', '', $pattern);
115 5
        return (bool)preg_match('/[*{?\[]/', $pattern);
116
    }
117
118
    /**
119
     * Escapes pattern characters in a string.
120
     *
121
     * @param string $string Source string.
122
     *
123
     * @return string String with pattern characters escaped.
124
     */
125 2
    public static function quote(string $string): string
126
    {
127 2
        return preg_replace('#([\\\\?*\\[\\]])#', '\\\\$1', $string);
128
    }
129
}
130