1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19

20
/**
21
 * PREG Regexp Engine.
22
 * Implements a regexp engine using PHP's preg_match(), preg_match_all(), and preg_replace() functions.
23
 *
24
 * @author  hans lellelid, hans@velum.net
25
 * @package phing.util.regexp
26
 */
27
class PregEngine implements RegexpEngine
28
{
29
    /**
30
     * Set to null by default to distinguish between false and not set
31
     *
32
     * @var boolean
33
     */
34
    private $ignoreCase = null;
35

36
    /**
37
     * Set to null by default to distinguish between false and not set
38
     *
39
     * @var boolean
40
     */
41
    private $multiline = null;
42

43
    /**
44
     * Pattern modifiers
45
     *
46
     * @link http://php.net/manual/en/reference.pcre.pattern.modifiers.php
47
     * @var  string
48
     */
49
    private $modifiers = null;
50

51
    /**
52
     * Set the limit.
53
     *
54
     * @var int
55
     */
56
    private $limit = -1;
57

58
    /**
59
     * Pattern delimiter.
60
     */
61
    public const DELIMITER = '`';
62

63
    /**
64
     * Sets pattern modifiers for regex engine
65
     *
66
     * @param  string $mods Modifiers to be applied to a given regex
67
     * @return void
68
     */
69 1
    public function setModifiers($mods)
70
    {
71 1
        $this->modifiers = (string) $mods;
72
    }
73

74
    /**
75
     * Gets pattern modifiers.
76
     *
77
     * @return string
78
     */
79 1
    public function getModifiers()
80
    {
81 1
        $mods = $this->modifiers;
82 1
        if ($this->getIgnoreCase()) {
83 1
            $mods .= 'i';
84 1
        } elseif ($this->getIgnoreCase() === false) {
85 1
            $mods = str_replace('i', '', $mods);
86
        }
87 1
        if ($this->getMultiline()) {
88 1
            $mods .= 's';
89 1
        } elseif ($this->getMultiline() === false) {
90 1
            $mods = str_replace('s', '', $mods);
91
        }
92
        // filter out duplicates
93 1
        $mods = preg_split('//', $mods, -1, PREG_SPLIT_NO_EMPTY);
94 1
        $mods = implode('', array_unique($mods));
95

96 1
        return $mods;
97
    }
98

99
    /**
100
     * Sets whether or not regex operation is case sensitive.
101
     *
102
     * @param  boolean $bit
103
     * @return void
104
     */
105 1
    public function setIgnoreCase($bit)
106
    {
107 1
        $this->ignoreCase = (bool) $bit;
108
    }
109

110
    /**
111
     * Gets whether or not regex operation is case sensitive.
112
     *
113
     * @return boolean
114
     */
115 1
    public function getIgnoreCase()
116
    {
117 1
        return $this->ignoreCase;
118
    }
119

120
    /**
121
     * Sets whether regexp should be applied in multiline mode.
122
     *
123
     * @param boolean $bit
124
     */
125 1
    public function setMultiline($bit)
126
    {
127 1
        $this->multiline = $bit;
128
    }
129

130
    /**
131
     * Gets whether regexp is to be applied in multiline mode.
132
     *
133
     * @return boolean
134
     */
135 1
    public function getMultiline()
136
    {
137 1
        return $this->multiline;
138
    }
139

140
    /**
141
     * Sets the maximum possible replacements for each pattern.
142
     *
143
     * @param int $limit
144
     */
145 1
    public function setLimit($limit)
146
    {
147 1
        $this->limit = $limit;
148
    }
149

150
    /**
151
     * Returns the maximum possible replacements for each pattern.
152
     *
153
     * @return int
154
     */
155 0
    public function getLimit()
156
    {
157 0
        return $this->limit;
158
    }
159

160
    /**
161
     * The pattern needs to be converted into PREG style -- which includes adding expression delims & any flags, etc.
162
     *
163
     * @param  string $pattern
164
     * @return string prepared pattern.
165
     */
166 1
    private function preparePattern($pattern)
167
    {
168 1
        $delimiterPattern = '/\\\\*' . self::DELIMITER . '/';
169

170
        // The following block escapes usages of the delimiter in the pattern if it's not already escaped.
171 1
        if (preg_match_all($delimiterPattern, $pattern, $matches, PREG_OFFSET_CAPTURE)) {
172 1
            $diffOffset = 0;
173

174 1
            foreach ($matches[0] as $match) {
175 1
                $str = $match[0];
176 1
                $offset = $match[1] + $diffOffset;
177

178 1
                $escStr = (strlen($str) % 2) ? '\\' . $str : $str; // This will increase an even number of backslashes, before a forward slash, to an odd number.  I.e. '\\/' becomes '\\\/'.
179

180 1
                $diffOffset += strlen($escStr) - strlen($str);
181

182 1
                $pattern = substr_replace($pattern, $escStr, $offset, strlen($str));
183
            }
184
        }
185

186 1
        return self::DELIMITER . $pattern . self::DELIMITER . $this->getModifiers();
187
    }
188

189
    /**
190
     * Matches pattern against source string and sets the matches array.
191
     *
192
     * @param  string $pattern The regex pattern to match.
193
     * @param  string $source The source string.
194
     * @param  array $matches The array in which to store matches.
195
     * @return boolean Success of matching operation.
196
     */
197 1
    public function match($pattern, $source, &$matches)
198
    {
199 1
        return preg_match($this->preparePattern($pattern), $source, $matches) > 0;
200
    }
201

202
    /**
203
     * Matches all patterns in source string and sets the matches array.
204
     *
205
     * @param  string $pattern The regex pattern to match.
206
     * @param  string $source The source string.
207
     * @param  array $matches The array in which to store matches.
208
     * @return boolean Success of matching operation.
209
     */
210 1
    public function matchAll($pattern, $source, &$matches)
211
    {
212 1
        return preg_match_all($this->preparePattern($pattern), $source, $matches) > 0;
213
    }
214

215
    /**
216
     * Replaces $pattern with $replace in $source string.
217
     * References to \1 group matches will be replaced with more preg-friendly
218
     * $1.
219
     *
220
     * @param  string $pattern The regex pattern to match.
221
     * @param  string $replace The string with which to replace matches.
222
     * @param  string $source The source string.
223
     * @return string The replaced source string.
224
     */
225 1
    public function replace($pattern, $replace, $source)
226
    {
227
        // convert \1 -> $1, because we want to use the more generic \1 in the XML
228
        // but PREG prefers $1 syntax.
229 1
        $replace = preg_replace('/\\\(\d+)/', '\$$1', $replace);
230

231 1
        return preg_replace($this->preparePattern($pattern), $replace, $source, $this->limit);
232
    }
233
}

Read our documentation on viewing source code .

Loading