wproot 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Rakefile +2 -0
- data/bin/wproot +7 -0
- data/lib/wproot.rb +11 -0
- data/lib/wproot/cli.rb +35 -0
- data/lib/wproot/compass.rb +15 -0
- data/lib/wproot/haml.rb +15 -0
- data/lib/wproot/version.rb +3 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/wproot_spec.rb +59 -0
- data/vendor/HamlPHP.php +7 -0
- data/vendor/HamlPHP/.gitignore +6 -0
- data/vendor/HamlPHP/MIT-LICENSE +22 -0
- data/vendor/HamlPHP/README.mkd +39 -0
- data/vendor/HamlPHP/src/HamlPHP/CommentNode.php +92 -0
- data/vendor/HamlPHP/src/HamlPHP/Compiler.php +109 -0
- data/vendor/HamlPHP/src/HamlPHP/ContentEvaluator/ContentEvaluator.php +16 -0
- data/vendor/HamlPHP/src/HamlPHP/ContentEvaluator/DefaultContentEvaluator.php +22 -0
- data/vendor/HamlPHP/src/HamlPHP/DoctypeNode.php +47 -0
- data/vendor/HamlPHP/src/HamlPHP/Element.php +618 -0
- data/vendor/HamlPHP/src/HamlPHP/ElementNode.php +222 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/CssFilter.php +31 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/Filter.php +18 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/FilterContainer.php +34 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/JavascriptFilter.php +29 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/PhpFilter.php +24 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/PlainFilter.php +46 -0
- data/vendor/HamlPHP/src/HamlPHP/FilterNode.php +29 -0
- data/vendor/HamlPHP/src/HamlPHP/HamlNode.php +75 -0
- data/vendor/HamlPHP/src/HamlPHP/HamlPHP.php +191 -0
- data/vendor/HamlPHP/src/HamlPHP/Helpers.php +136 -0
- data/vendor/HamlPHP/src/HamlPHP/Interpolation.php +71 -0
- data/vendor/HamlPHP/src/HamlPHP/NodeFactory.php +80 -0
- data/vendor/HamlPHP/src/HamlPHP/RootNode.php +133 -0
- data/vendor/HamlPHP/src/HamlPHP/Storage/DontEvaluateStorage.php +68 -0
- data/vendor/HamlPHP/src/HamlPHP/Storage/FileStorage.php +74 -0
- data/vendor/HamlPHP/src/HamlPHP/Storage/Storage.php +24 -0
- data/vendor/HamlPHP/src/HamlPHP/TagNode.php +125 -0
- data/vendor/HamlPHP/src/HamlPHP/Util/BaseException.php +340 -0
- data/vendor/HamlPHP/src/HamlPHP/Util/BaseObject.php +94 -0
- data/vendor/HamlPHP/src/HamlPHP/Util/StringScanner.php +989 -0
- data/wproot.gemspec +21 -0
- metadata +126 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
<?php
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @author Saulo Vallory <email@saulovallory.com>
|
5
|
+
*/
|
6
|
+
require_once dirname(__FILE__) . '/BaseException.php';
|
7
|
+
|
8
|
+
class UndefinedPropertyException extends BaseException {
|
9
|
+
/**
|
10
|
+
* @param string $class
|
11
|
+
* @param string $property
|
12
|
+
*/
|
13
|
+
public function __construct($class, $property) {
|
14
|
+
parent::__construct("Trying to access an undefined property ($class::$property) on {{guiltyFile}} at line {{guiltyLine}}");
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Thrown when trying to set a read-only property.
|
20
|
+
*/
|
21
|
+
class ReadOnlyPropertyException extends BaseException {
|
22
|
+
/**
|
23
|
+
* @param string $class
|
24
|
+
* @param string $property
|
25
|
+
*/
|
26
|
+
public function __construct($class, $property) {
|
27
|
+
parent::__construct("Trying to set a read-only property ($class::$property) on {{guiltyFile}} at line {{guiltyLine}}");
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Provides default __get and __set magic methods
|
33
|
+
* You can define a protected array $magic_get_methods in a subclass to
|
34
|
+
* specify a "magic property" -> "get method" relation.
|
35
|
+
* Ex:
|
36
|
+
* <code>
|
37
|
+
* protected $magic_get_methods = array(
|
38
|
+
* 'eos' => 'endOfStream'
|
39
|
+
* );
|
40
|
+
* </code>
|
41
|
+
*/
|
42
|
+
abstract class BaseObject
|
43
|
+
{
|
44
|
+
public function __get($name)
|
45
|
+
{
|
46
|
+
if(isset($this->magic_get_methods[$name])) {
|
47
|
+
$methods = array($this->magic_get_methods[$name]);
|
48
|
+
}
|
49
|
+
else {
|
50
|
+
$name = ucfirst($name);
|
51
|
+
$methods = array("get$name", "is$name", "has$name");
|
52
|
+
}
|
53
|
+
|
54
|
+
foreach($methods as $m)
|
55
|
+
{
|
56
|
+
if(method_exists($this, $m)) {
|
57
|
+
return $this->$m();
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
$ex = new UndefinedPropertyException(get_class($this), $name);
|
62
|
+
$btrace = debug_backtrace();
|
63
|
+
$ex->setGuiltyFile($btrace[0]['file']);
|
64
|
+
$ex->setGuiltyLine($btrace[0]['line']);
|
65
|
+
throw $ex;
|
66
|
+
}
|
67
|
+
|
68
|
+
public function __set($name,$value)
|
69
|
+
{
|
70
|
+
$setter='set'.$name;
|
71
|
+
$boolSetter = "is$name";
|
72
|
+
|
73
|
+
if(method_exists($this,$setter))
|
74
|
+
{
|
75
|
+
$this->$setter($value);
|
76
|
+
}
|
77
|
+
else if(method_exists($this,'get'.$name))
|
78
|
+
{
|
79
|
+
$ex = new ReadOnlyPropertyException(get_class($this), $name);
|
80
|
+
$btrace = debug_backtrace();
|
81
|
+
$ex->setGuiltyFile($btrace[0]['file']);
|
82
|
+
$ex->setGuiltyLine($btrace[0]['line']);
|
83
|
+
throw $ex;
|
84
|
+
}
|
85
|
+
else
|
86
|
+
{
|
87
|
+
$ex = new UndefinedPropertyException(get_class($this), $name);
|
88
|
+
$btrace = debug_backtrace();
|
89
|
+
$ex->setGuiltyFile($btrace[0]['file']);
|
90
|
+
$ex->setGuiltyLine($btrace[0]['line']);
|
91
|
+
throw $ex;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
@@ -0,0 +1,989 @@
|
|
1
|
+
<?php
|
2
|
+
|
3
|
+
require_once 'BaseObject.php';
|
4
|
+
|
5
|
+
/** @class StringScanner
|
6
|
+
* @nosubgrouping
|
7
|
+
* StringScanner provides for lexical scanning operations on a String.
|
8
|
+
* This class is a port of Ruby's StringScan class. So the documentation was "stolen" from there.
|
9
|
+
* Here is an example of its usage:
|
10
|
+
*
|
11
|
+
* @code
|
12
|
+
* $s = new StringScanner('This is an example string');
|
13
|
+
* $s->eos; # -> false
|
14
|
+
*
|
15
|
+
* echo $s->scan('/\w+/'); # -> "This"
|
16
|
+
* echo $s->scan('/\w+/'); # -> null
|
17
|
+
* echo $s->scan('/\s+/'); # -> " "
|
18
|
+
* echo $s->scan('/\s+/'); # -> null
|
19
|
+
* echo $s->scan('/\w+/'); # -> "is"
|
20
|
+
* $s->eos; # -> false
|
21
|
+
*
|
22
|
+
* echo $s->scan('/\s+/'); # -> " "
|
23
|
+
* echo $s->scan('/\w+/'); # -> "an"
|
24
|
+
* echo $s->scan('/\s+/'); # -> " "
|
25
|
+
* echo $s->scan('/\w+/'); # -> "example"
|
26
|
+
* echo $s->scan('/\s+/'); # -> " "
|
27
|
+
* echo $s->scan('/\w+/'); # -> "string"
|
28
|
+
* $s->eos; # -> true
|
29
|
+
*
|
30
|
+
* echo $s->scan('/\s+/'); # -> null
|
31
|
+
* echo $s->scan('/\w+/'); # -> null
|
32
|
+
* @endcode
|
33
|
+
*
|
34
|
+
* <p>
|
35
|
+
* Scanning a @mlink{$string} means remembering the position of a scan @mlink{$pointer}, which is just an index.
|
36
|
+
* The point of scanning is to move forward a bit at a time, so matches are
|
37
|
+
* sought after the scan @mlink{$pointer}; usually immediately after it.
|
38
|
+
* </p>
|
39
|
+
*
|
40
|
+
* <p>
|
41
|
+
* Given the string "test string", here are the pertinent scan @mlink{$pointer} positions:
|
42
|
+
* </p>
|
43
|
+
*
|
44
|
+
* <pre>
|
45
|
+
* t e s t s t r i n g
|
46
|
+
* 0 1 2 ... 1
|
47
|
+
* 0
|
48
|
+
* </pre>
|
49
|
+
*
|
50
|
+
* <p>
|
51
|
+
* When you {@link scan()} for a pattern (a regular expression), the match must occur at the character after the scan @mlink{$pointer}.
|
52
|
+
* If you use {@link scanUntil()}, then the match can occur anywhere after the scan pointer. In both cases, the scan @mlink{$pointer} moves <em>just beyond</em>
|
53
|
+
* the last character of the match, ready to <a href="StringScanner.html#M003869">scan</a> again from the next character
|
54
|
+
* onwards. This is demonstrated by the example above.
|
55
|
+
* </p>
|
56
|
+
*
|
57
|
+
* <h2>Method_Categories Method Categories</h2>
|
58
|
+
*
|
59
|
+
* There are other methods besides the plain scanners. You can look ahead in
|
60
|
+
* the <a href="StringScanner.html#M003861">string</a> without actually
|
61
|
+
* scanning. You can access the most recent match. You can modify the @mlink{$string} being scanned,
|
62
|
+
* {@link reset()} or {@link terminate()} the scanner, find out or
|
63
|
+
* change the position of the scan @mlink{$pointer}, {@link skip()} ahead, and so on.
|
64
|
+
*
|
65
|
+
* @par Advancing the Scan Pointer
|
66
|
+
*
|
67
|
+
* - {@link getch()}
|
68
|
+
* - {@link scan()}
|
69
|
+
* - {@link scanUntil()}
|
70
|
+
* - {@link skip()}
|
71
|
+
* - {@link skipUntil()}
|
72
|
+
*
|
73
|
+
* @par Looking Ahead
|
74
|
+
*
|
75
|
+
* - {@link check()}
|
76
|
+
* - {@link checkUntil()}
|
77
|
+
* - {@link exist()}
|
78
|
+
* - {@link match()}
|
79
|
+
* - {@link peek()}
|
80
|
+
*
|
81
|
+
* @par Finding Where we Are
|
82
|
+
*
|
83
|
+
* - @mlink{$bol} or {@link isBeginningOfLine()}
|
84
|
+
* - {@link eos}
|
85
|
+
* - @mlink{$rest}
|
86
|
+
* - {@link restSize()}
|
87
|
+
* - @mlink{$pos} or @mlink{$pointer}
|
88
|
+
*
|
89
|
+
* @par Setting Where we Are
|
90
|
+
*
|
91
|
+
* - {@link reset()}
|
92
|
+
* - {@link terminate()}
|
93
|
+
* - @mlink{$pos}
|
94
|
+
*
|
95
|
+
* @par Match Data
|
96
|
+
*
|
97
|
+
* - {@link matched()}
|
98
|
+
* - @mlink{$matchedSize} or {@link getMatchedSize()}
|
99
|
+
* - [] (You can use array like syntax to <em>get</em> the last match and it's subgroups
|
100
|
+
* - {@link preMatch()}
|
101
|
+
* - {@link postMatch()}
|
102
|
+
*
|
103
|
+
* @par Miscellaneous
|
104
|
+
*
|
105
|
+
* - {@link concat()}
|
106
|
+
* - @mlink{$string}
|
107
|
+
* - {@link unscan()}
|
108
|
+
*
|
109
|
+
* There are aliases to several of the methods.
|
110
|
+
*
|
111
|
+
* @todo Implement byte reading
|
112
|
+
*
|
113
|
+
* @author Saulo Vallory <email@saulovallory.com>
|
114
|
+
*
|
115
|
+
* @property-read bool $beginningOfLine Returns true if the scan @mlink{$pointer} is at the beginning of the line
|
116
|
+
* @property-read bool $bol Returns true if the scan @mlink{$pointer} is at the beginning of a new line.
|
117
|
+
* @property-read bool $eos Returns true if the scan @mlink{$pointer} is at the end of the string.
|
118
|
+
* @property-read int $matchedSize Returns the size of the most recent match (see @mlink{$matched} or {@link getMatched()}), or null if there was no recent match.
|
119
|
+
* @property-read int $pointer Returns true if the scan @mlink{$pointer} is at the beginning of a new line.
|
120
|
+
* @property-read int $pos Returns true if the scan @mlink{$pointer} is at the beginning of a new line.
|
121
|
+
* @property-read string $rest Returns the "rest" of the string (i.e. everything after the scan @mlink{$pointer}). If there is no more data (@mlink{$eos} = true), it returns "".
|
122
|
+
* @property-read string $restSize Returns the size of the "rest" of the string.
|
123
|
+
* @property string $string Returns the string being scanned.
|
124
|
+
* @property-read string $matched Returns true if the last match was successful.
|
125
|
+
*/
|
126
|
+
class StringScanner extends BaseObject implements ArrayAccess
|
127
|
+
{
|
128
|
+
/** \name Magic Properties
|
129
|
+
* @{
|
130
|
+
*/
|
131
|
+
/** @property read_only bool $beginningOfLine
|
132
|
+
* @brief Returns true if the scan @mlink{$pointer} is at the beginning of the line
|
133
|
+
* @memberof StringScanner
|
134
|
+
* @readonly
|
135
|
+
*/
|
136
|
+
|
137
|
+
/** @property read_only bool $bol
|
138
|
+
* @brief Returns true if the scan @mlink{$pointer} is at the beginning of a new line.
|
139
|
+
* @memberof StringScanner
|
140
|
+
* @readonly
|
141
|
+
*/
|
142
|
+
|
143
|
+
/** @property read_only bool $eos
|
144
|
+
* @brief Returns true if the scan @mlink{$pointer} is at the end of the string.
|
145
|
+
* @memberof StringScanner
|
146
|
+
* @readonly
|
147
|
+
*/
|
148
|
+
|
149
|
+
/** @property read_only int $matchedSize
|
150
|
+
* @brief Returns the size of the most recent match (see @mlink{$matched} or {@link getMatched()}), or null if there was no recent match.
|
151
|
+
* @memberof StringScanner
|
152
|
+
* @readonly
|
153
|
+
*/
|
154
|
+
|
155
|
+
/**
|
156
|
+
* @property read_only int $pointer
|
157
|
+
* @brief Returns the current pointer position.
|
158
|
+
* @memberof StringScanner
|
159
|
+
* @readonly
|
160
|
+
*/
|
161
|
+
|
162
|
+
/** @property int $pos
|
163
|
+
* @brief Returns true if the scan @mlink{$pointer} is at the beginning of a new line.
|
164
|
+
* @memberof StringScanner
|
165
|
+
*/
|
166
|
+
|
167
|
+
/** @property read_only string $rest
|
168
|
+
* @brief Returns the "rest" of the string (i.e. everything after the scan @mlink{$pointer}). If there is no more data (@mlink{$eos} = true), it returns "".
|
169
|
+
* @memberof StringScanner
|
170
|
+
* @readonly
|
171
|
+
*/
|
172
|
+
|
173
|
+
/** @property read_only string $restSize
|
174
|
+
* @brief Returns the size of the "rest" of the string.
|
175
|
+
* @memberof StringScanner
|
176
|
+
* @readonly
|
177
|
+
*/
|
178
|
+
|
179
|
+
/** @property string $string
|
180
|
+
* @brief Returns the string being scanned.
|
181
|
+
* @memberof StringScanner
|
182
|
+
*/
|
183
|
+
|
184
|
+
/** @property read_only string $matched
|
185
|
+
* @brief Returns true if the last match was successful.
|
186
|
+
* @memberof StringScanner
|
187
|
+
* @readonly
|
188
|
+
*/
|
189
|
+
/** @} */
|
190
|
+
|
191
|
+
private $_string;
|
192
|
+
|
193
|
+
private $_curr;
|
194
|
+
|
195
|
+
private $_prev;
|
196
|
+
|
197
|
+
/**
|
198
|
+
* Last match and it's subgroups
|
199
|
+
* @var array
|
200
|
+
*/
|
201
|
+
private $_matches;
|
202
|
+
|
203
|
+
/**
|
204
|
+
* The beginning pos of the last match
|
205
|
+
* @var int
|
206
|
+
*/
|
207
|
+
private $_lastMatchBeg;
|
208
|
+
|
209
|
+
/**
|
210
|
+
* The ending pos of the last match
|
211
|
+
* @var int
|
212
|
+
*/
|
213
|
+
private $_lastMatchEnd;
|
214
|
+
|
215
|
+
private $_rest;
|
216
|
+
|
217
|
+
/**
|
218
|
+
* The length of the {@link string} being parsed
|
219
|
+
* @var int
|
220
|
+
*/
|
221
|
+
private $_size;
|
222
|
+
|
223
|
+
private $_restSize;
|
224
|
+
|
225
|
+
private $_encoding = null;
|
226
|
+
|
227
|
+
protected $magic_get_methods = array(
|
228
|
+
'bol' => 'isBeginningOfLine',
|
229
|
+
'beginningOfLine' => 'isBeginningOfLine',
|
230
|
+
'pointer' => 'getPos',
|
231
|
+
'eos' => 'isEos',
|
232
|
+
);
|
233
|
+
|
234
|
+
/**
|
235
|
+
* Creates a new StringScanner object to scan over the given $string.
|
236
|
+
* @param string $str The string to be scanned
|
237
|
+
* @param string $encoding The encoding of the string
|
238
|
+
*/
|
239
|
+
public function __construct($str, $encoding = null)
|
240
|
+
{
|
241
|
+
if($encoding)
|
242
|
+
$this->_encoding = $encoding;
|
243
|
+
else
|
244
|
+
$this->_encoding = mb_internal_encoding();
|
245
|
+
|
246
|
+
$this->_string = $str;
|
247
|
+
$this->reset();
|
248
|
+
}
|
249
|
+
|
250
|
+
/**
|
251
|
+
* @internal
|
252
|
+
* @param string $regex The regular expression
|
253
|
+
* @param bool $update_ptr Wheter to update the pointer or not
|
254
|
+
* @param bool $get_str Wheter to return the matched string or the position
|
255
|
+
* @param bool $head_only Match only at the beginning of the string
|
256
|
+
* @return mixed Either the matched string (if $return_string is true) or the end position of the match
|
257
|
+
*/
|
258
|
+
private function doScan($regex, $update_ptr, $get_str, $head_only)
|
259
|
+
{
|
260
|
+
if($this->eos)
|
261
|
+
return null;
|
262
|
+
|
263
|
+
if ($head_only) {
|
264
|
+
$regex = $regex[0] . '^' . mb_substr($regex, 1, mb_strlen($regex), $this->_encoding);
|
265
|
+
}
|
266
|
+
else
|
267
|
+
{
|
268
|
+
$delim = $regex[0];
|
269
|
+
$end_pos = strrpos($regex, $delim);
|
270
|
+
|
271
|
+
$regex = "$delim.*?(".substr($regex, 1, $end_pos-1).")$delim".substr($regex, $end_pos+1);
|
272
|
+
}
|
273
|
+
|
274
|
+
$ret = preg_match($regex, $this->_rest, $this->_matches);
|
275
|
+
|
276
|
+
if ($ret === false)
|
277
|
+
throw new Exception(preg_last_error());
|
278
|
+
|
279
|
+
if ($ret == 0) {
|
280
|
+
// not matched
|
281
|
+
$this->_clear_matched();
|
282
|
+
return null;
|
283
|
+
}
|
284
|
+
|
285
|
+
$this->_matched($update_ptr);
|
286
|
+
|
287
|
+
if ($get_str) {
|
288
|
+
return mb_substr($this->_string, $this->_prev, $this->_lastMatchEnd - $this->_prev, $this->_encoding);
|
289
|
+
}
|
290
|
+
else {
|
291
|
+
return $this->_lastMatchEnd - $this->_prev;
|
292
|
+
}
|
293
|
+
}
|
294
|
+
|
295
|
+
/**
|
296
|
+
* @internal
|
297
|
+
* NEEDS to be called whenever the scanner does a new match
|
298
|
+
* Update optimization vars based on the last match
|
299
|
+
*
|
300
|
+
* @param bool $update_curr Wheter to update the pointer or not
|
301
|
+
*/
|
302
|
+
private function _matched($update_curr)
|
303
|
+
{
|
304
|
+
$this->_prev = $this->_curr;
|
305
|
+
$this->_lastMatchBeg = $this->_curr + (empty($this->_matches[0]) ? 0 : mb_strpos($this->_rest, $this->_matches[0], 0, $this->_encoding));
|
306
|
+
$this->_lastMatchEnd = $this->_lastMatchBeg + mb_strlen($this->_matches[0], $this->_encoding);
|
307
|
+
|
308
|
+
if($update_curr)
|
309
|
+
{
|
310
|
+
$this->_curr = $this->_lastMatchEnd;
|
311
|
+
$this->_rest = mb_substr($this->_string, $this->_curr, $this->_size, $this->_encoding);
|
312
|
+
$this->_restSize = mb_strlen($this->_rest, $this->_encoding);
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
316
|
+
private function _clear_matched()
|
317
|
+
{
|
318
|
+
$this->_matches = null;
|
319
|
+
$this->_lastMatchBeg = null;
|
320
|
+
$this->_lastMatchEnd = null;
|
321
|
+
}
|
322
|
+
|
323
|
+
private function _string_updated($keep_pointer)
|
324
|
+
{
|
325
|
+
if($keep_pointer)
|
326
|
+
{
|
327
|
+
$this->_size = mb_strlen($this->_string, $this->_encoding);
|
328
|
+
$this->_rest = mb_substr($this->_string, $this->_curr, $this->_size, $this->_encoding);
|
329
|
+
$this->_restSize = mb_strlen($this->_rest, $this->_encoding);
|
330
|
+
|
331
|
+
if($this->_curr > $this->_size)
|
332
|
+
throw new Exception('The operation resulted in an invalid pointer position!');
|
333
|
+
}
|
334
|
+
else
|
335
|
+
{
|
336
|
+
$this->_prev = null;
|
337
|
+
$this->_curr = 0;
|
338
|
+
$this->_rest = $this->_string;
|
339
|
+
$this->_restSize = $this->_size = mb_strlen($this->_string, $this->_encoding);
|
340
|
+
$this->_matches = $this->_lastMatchBeg = $this->_lastMatchEnd = null;
|
341
|
+
}
|
342
|
+
}
|
343
|
+
|
344
|
+
/* ArrayAccess methods */
|
345
|
+
|
346
|
+
/**
|
347
|
+
* Wether the n-th group was caught or not in the last match.
|
348
|
+
* 0 stands for the whole match.
|
349
|
+
* This method is executed when using isset() or empty().
|
350
|
+
*
|
351
|
+
* @param int $offset
|
352
|
+
*/
|
353
|
+
public function offsetExists($offset)
|
354
|
+
{
|
355
|
+
return isset($this->_matches[$offset]);
|
356
|
+
}
|
357
|
+
|
358
|
+
/**
|
359
|
+
* Implements ArrayAccess
|
360
|
+
* Return the n-th subgroup in the most recent match.
|
361
|
+
* @code
|
362
|
+
* $s = new StringScanner("Fri Dec 12 1975 14:39");
|
363
|
+
* $s->scan('/(\w+) (\w+) (\d+) /'); # -> "Fri Dec 12 "
|
364
|
+
* echo $s[0]; # -> "Fri Dec 12 "
|
365
|
+
* echo $s[1]; # -> "Fri"
|
366
|
+
* echo $s[2]; # -> "Dec"
|
367
|
+
* echo $s[3]; # -> "12"
|
368
|
+
* echo $s->postMatch(); # -> "1975 14:39"
|
369
|
+
* echo $s->preMatch(); # -> ""
|
370
|
+
* @endcode
|
371
|
+
* @param int $offset
|
372
|
+
*/
|
373
|
+
public function offsetGet($offset)
|
374
|
+
{
|
375
|
+
return isset($this->_matches[$offset]) ? $this->_matches[$offset] : null;
|
376
|
+
}
|
377
|
+
|
378
|
+
/**
|
379
|
+
* Calling this method will throw an exception.
|
380
|
+
* You can't set the value of the last match.
|
381
|
+
*/
|
382
|
+
public function offsetSet($offset, $value)
|
383
|
+
{
|
384
|
+
throw new Exception("You can't set the value of the last match.");
|
385
|
+
}
|
386
|
+
|
387
|
+
/**
|
388
|
+
* Calling this method will throw an exception.
|
389
|
+
* You can't unset the value of the last match.
|
390
|
+
*/
|
391
|
+
public function offsetUnset($offset)
|
392
|
+
{
|
393
|
+
throw new Exception("You can't unset the value of the last match.");
|
394
|
+
}
|
395
|
+
|
396
|
+
/* / ArrayAccess methods */
|
397
|
+
|
398
|
+
/**
|
399
|
+
* Returns true if the scan @mlink{$pointer} is at the beginning of the line.
|
400
|
+
* @magicalias{$bol}
|
401
|
+
*
|
402
|
+
* @code
|
403
|
+
* $s = new StringScanner("test\ntest\n");
|
404
|
+
* $s->bol(); # => true
|
405
|
+
* $s->scan('/te/');
|
406
|
+
* $s->bol(); # => false
|
407
|
+
* $s->scan('/st\n/');
|
408
|
+
* $s->bol(); # => true
|
409
|
+
* $s->terminate();
|
410
|
+
* $s->bol(); # => true
|
411
|
+
* @endcode
|
412
|
+
*
|
413
|
+
* @return bool
|
414
|
+
*/
|
415
|
+
public function isBeginningOfLine() {
|
416
|
+
return ($this->_curr == 0 || $this->_string[$this->_curr-1] == "\n");
|
417
|
+
}
|
418
|
+
|
419
|
+
/**
|
420
|
+
* This returns the value that scan would return, without advancing the scan pointer. The match register is affected, though.
|
421
|
+
* @code
|
422
|
+
* $s = new StringScanner("Fri Dec 12 1975 14:39");
|
423
|
+
* $s->check('/Fri/'); # -> "Fri"
|
424
|
+
* $s->pos; # -> 0
|
425
|
+
* $s->matched; # -> "Fri"
|
426
|
+
* $s->check('/12/'); # -> null
|
427
|
+
* $s->matched; # -> null
|
428
|
+
* @endcode
|
429
|
+
* Mnemonic: it "checks" to see whether a scan will return a value.
|
430
|
+
*
|
431
|
+
* @param string $pattern
|
432
|
+
*/
|
433
|
+
public function check($pattern) {
|
434
|
+
return $this->doScan($pattern, false, true, true);
|
435
|
+
}
|
436
|
+
|
437
|
+
/**
|
438
|
+
* This returns the value that {@link scanUntil()} would return, without advancing the scan @mlink{$pointer}.
|
439
|
+
* The match register is affected, though.
|
440
|
+
* @code
|
441
|
+
* $s = new StringScanner("Fri Dec 12 1975 14:39");
|
442
|
+
* $s->checkUntil('/12/'); # -> "Fri Dec 12"
|
443
|
+
* $s->pos; # -> 0
|
444
|
+
* $s->matched; # -> 12
|
445
|
+
* @endcode
|
446
|
+
* Mnemonic: it "checks" to see whether a scanUntil will return a value.
|
447
|
+
*
|
448
|
+
* @param string $pattern
|
449
|
+
* @return string
|
450
|
+
*/
|
451
|
+
public function checkUntil($pattern) {
|
452
|
+
return $this->doScan($pattern, false, true, false);
|
453
|
+
}
|
454
|
+
|
455
|
+
/**
|
456
|
+
* Appends $str to the @mlink{$string} being scanned.
|
457
|
+
* This method does not affect scan @mlink{$pointer}.
|
458
|
+
* @code
|
459
|
+
* $s = new StringScanner("Fri Dec 12 1975 14:39");
|
460
|
+
* $s->scan('/Fri /');
|
461
|
+
* $s->concat(" +1000 GMT");
|
462
|
+
* $s->string; // -> "Fri Dec 12 1975 14:39 +1000 GMT"
|
463
|
+
* $s->scan('/Dec/'); // -> "Dec"
|
464
|
+
* @endcode
|
465
|
+
* @param $str
|
466
|
+
*/
|
467
|
+
public function concat($str)
|
468
|
+
{
|
469
|
+
$this->_string .= $str;
|
470
|
+
$this->_string_updated(true);
|
471
|
+
}
|
472
|
+
|
473
|
+
/**
|
474
|
+
* Returns true if the scan @mlink{$pointer} is at the end of the string.
|
475
|
+
* @code
|
476
|
+
* $s = new StringScanner('test string');
|
477
|
+
* echo $s->eos; # => false
|
478
|
+
* $s->scan('/test/');
|
479
|
+
* echo $s->eos; # => false
|
480
|
+
* $s->terminate();
|
481
|
+
* echo $s->eos; # => true
|
482
|
+
* @endcode
|
483
|
+
*
|
484
|
+
* @return bool
|
485
|
+
*/
|
486
|
+
protected function isEos() {
|
487
|
+
return $this->_curr == $this->_size;
|
488
|
+
}
|
489
|
+
|
490
|
+
/**
|
491
|
+
* Looks ahead to see if the $pattern exists anywhere in the @mlink{$string}, without advancing the scan @mlink{$pointer}.
|
492
|
+
* This predicts whether a {@link scanUntil()} will return a value.
|
493
|
+
* @code
|
494
|
+
* $s = new StringScanner('test string');
|
495
|
+
* $s->exist('/s/'); # -> 3
|
496
|
+
* $s->scan('/test/'); # -> "test"
|
497
|
+
* $s->exist('/s/'); # -> 2
|
498
|
+
* $s->exist('/e/'); # -> null
|
499
|
+
* @endcode
|
500
|
+
*
|
501
|
+
* @param string $pattern
|
502
|
+
*/
|
503
|
+
public function exist($pattern) {
|
504
|
+
return $this->doScan($pattern, false, false, false);
|
505
|
+
}
|
506
|
+
|
507
|
+
/* Scath of getByte method.
|
508
|
+
* Important!!!
|
509
|
+
* The implementation of this method affects getch() because using it can leave part of a multi-byte character in the $_rest of the string.
|
510
|
+
*
|
511
|
+
* Scans one byte and returns it. This method is not multibyte character sensitive and will not work if mbstring.func_overload is set to ON in php.ini.
|
512
|
+
* @code
|
513
|
+
* $s = new StringScanner('ab')
|
514
|
+
* $s->get_byte; # => "a"
|
515
|
+
* $s->get_byte; # => "b"
|
516
|
+
* $s->get_byte; # => null
|
517
|
+
*
|
518
|
+
* $KCODE = 'EUC'
|
519
|
+
* $s = new StringScanner("\244\242")
|
520
|
+
* $s->get_byte; # => "\244"
|
521
|
+
* $s->get_byte; # => "\242"
|
522
|
+
* $s->get_byte; # => null
|
523
|
+
* @endcode
|
524
|
+
*
|
525
|
+
* @see getch()
|
526
|
+
* @return string
|
527
|
+
*
|
528
|
+
public function getByte() {
|
529
|
+
|
530
|
+
$this->_matches = null;
|
531
|
+
|
532
|
+
if ($this->_eos)
|
533
|
+
return null;
|
534
|
+
|
535
|
+
$this->prev = $this->curr;
|
536
|
+
$this->curr++;
|
537
|
+
|
538
|
+
$this->_matches = array($this->_rest[$this->_prev]);
|
539
|
+
|
540
|
+
return $this->_rest[$this->_prev];
|
541
|
+
}
|
542
|
+
*/
|
543
|
+
|
544
|
+
/**
|
545
|
+
* Scans one character and returns it. This method is multibyte character sensitive.
|
546
|
+
* @code
|
547
|
+
* $s = new StringScanner("ab");
|
548
|
+
* $s->getch(); # => "a"
|
549
|
+
* $s->getch(); # => "b"
|
550
|
+
* $s->getch(); # => null
|
551
|
+
*
|
552
|
+
* $s = new StringScanner("\244\242");
|
553
|
+
* $s->getch(); # => "\244\242" # Japanese hira-kana "A" in EUC-JP
|
554
|
+
* $s->getch(); # => null
|
555
|
+
* @endcode
|
556
|
+
*/
|
557
|
+
public function getch() {
|
558
|
+
if($this->eos)
|
559
|
+
return null;
|
560
|
+
|
561
|
+
$ch = mb_substr($this->_rest, 0, 1, $this->_encoding);
|
562
|
+
$this->_matches[0] = $ch;
|
563
|
+
$this->_matched(true);
|
564
|
+
|
565
|
+
return $ch;
|
566
|
+
}
|
567
|
+
|
568
|
+
/**
|
569
|
+
* Returns a string that represents the StringScanner object, showing:
|
570
|
+
* - the current position
|
571
|
+
* - the size of the string
|
572
|
+
* - the characters surrounding the scan pointer
|
573
|
+
* @code
|
574
|
+
* $s = new StringScanner("Fri Dec 12 1975 14:39");
|
575
|
+
* $s->inspect(); # -> '#<StringScanner 0/21 @ "Fri D...">'
|
576
|
+
* $s->scanUntil('/12/'); # -> "Fri Dec 12"
|
577
|
+
* $s->inspect(); # -> '#<StringScanner 10/21 "...ec 12" @ " 1975...">'
|
578
|
+
* @endcode
|
579
|
+
*/
|
580
|
+
public function inspect() {
|
581
|
+
$s = "#<StringScanner {$this->_curr}/{$this->_size} ";
|
582
|
+
|
583
|
+
if($this->_curr > 0)
|
584
|
+
{
|
585
|
+
$s .= '"';
|
586
|
+
if($this->_curr > 5)
|
587
|
+
$s .= '...';
|
588
|
+
$s .= mb_substr($this->_string, $this->_curr-5, 5, $this->_encoding).'" ';
|
589
|
+
}
|
590
|
+
|
591
|
+
$s .= '@ ';
|
592
|
+
|
593
|
+
if($this->_curr < $this->_size)
|
594
|
+
{
|
595
|
+
$s .= '"'.mb_substr($this->_rest, 0, 5, $this->_encoding);
|
596
|
+
if($this->_restSize > 5)
|
597
|
+
$s .= '...';
|
598
|
+
$s .= '">';
|
599
|
+
}
|
600
|
+
|
601
|
+
return $s;
|
602
|
+
}
|
603
|
+
|
604
|
+
/**
|
605
|
+
* Tests whether the given $pattern is matched from the current scan @mlink{$pointer}.
|
606
|
+
* Returns the length of the match, or <pre>null</pre>. The scan @mlink{$pointer} is not advanced.
|
607
|
+
* @code
|
608
|
+
* $s = new StringScanner('test string');
|
609
|
+
* echo $s->match('/\w+/'); # -> 4
|
610
|
+
* echo $s->match('/\w+/'); # -> 4
|
611
|
+
* echo $s->match('/\s+/'); # -> null
|
612
|
+
* @endcode
|
613
|
+
*
|
614
|
+
* @param string $pattern
|
615
|
+
* @return int
|
616
|
+
*/
|
617
|
+
public function match($pattern) {
|
618
|
+
return $this->doScan($pattern, false, false, true);
|
619
|
+
}
|
620
|
+
|
621
|
+
/**
|
622
|
+
* Returns true if the last match was successful.
|
623
|
+
* @code
|
624
|
+
* $s = new StringScanner('test string');
|
625
|
+
* $s->match('/\w+/'); # => 4
|
626
|
+
* $s->matched(); # => true
|
627
|
+
* $s->matched; # => "test"
|
628
|
+
* $s->match('/\d+/'); # => null
|
629
|
+
* $s->matched(); # => false
|
630
|
+
* @endcode
|
631
|
+
* @return bool
|
632
|
+
*/
|
633
|
+
public function matched() {
|
634
|
+
return isset($this->_matches[0]);
|
635
|
+
}
|
636
|
+
|
637
|
+
/**
|
638
|
+
* Returns the last matched string.
|
639
|
+
* @code
|
640
|
+
* $s = new StringScanner('test string');
|
641
|
+
* $s->match('/\w+/'); # -> 4
|
642
|
+
* $s->matched; # -> "test"
|
643
|
+
* @endcode
|
644
|
+
* @return string
|
645
|
+
*/
|
646
|
+
public function getMatched() {
|
647
|
+
if(isset($this->_matches[0]))
|
648
|
+
return $this->_matches[0];
|
649
|
+
return null;
|
650
|
+
}
|
651
|
+
|
652
|
+
/**
|
653
|
+
* Returns the size of the most recent match (see matched), or null if there was no recent match.
|
654
|
+
* @code
|
655
|
+
* $s = new StringScanner('test string');
|
656
|
+
* $s->check('/\w+/'); # -> "test"
|
657
|
+
* $s->matchedSize; # -> 4
|
658
|
+
* $s->check('/\d+/'); # -> null
|
659
|
+
* $s->matchedSize; # -> null
|
660
|
+
* @endcode
|
661
|
+
* @return int
|
662
|
+
*/
|
663
|
+
public function getMatchedSize() {
|
664
|
+
if(isset($this->_matches[0]))
|
665
|
+
return mb_strlen($this->_matches[0], $this->_encoding);
|
666
|
+
|
667
|
+
return null;
|
668
|
+
}
|
669
|
+
|
670
|
+
/**
|
671
|
+
* Extracts a string corresponding to <tt>mb_substr(@mlink{$rest}, 0, $len)</tt>, without
|
672
|
+
* advancing the scan pointer.
|
673
|
+
* @code
|
674
|
+
* $s = new StringScanner('test string');
|
675
|
+
* $s->peek(7) # => "test st"
|
676
|
+
* $s->peek(7) # => "test st"
|
677
|
+
* @endcode
|
678
|
+
*
|
679
|
+
* @param $len
|
680
|
+
* @return string
|
681
|
+
*/
|
682
|
+
public function peek($len)
|
683
|
+
{
|
684
|
+
if($this->eos)
|
685
|
+
return null;
|
686
|
+
|
687
|
+
return mb_substr($this->_rest, $this->_curr, $len, $this->_encoding);
|
688
|
+
}
|
689
|
+
|
690
|
+
/**
|
691
|
+
* Returns the character position of the scan @mlink{$pointer}. In the '{@link reset() reset}' position, this
|
692
|
+
* value is zero. In the '{@link terminate() terminated}' position (i.e. the string is exhausted),
|
693
|
+
* this value is the size of the @mlink{$string}.
|
694
|
+
* @magicalias{$pos, $pointer}
|
695
|
+
*
|
696
|
+
* In short, it's a 0-based index into the @mlink{$string}.
|
697
|
+
* @code
|
698
|
+
* $s = new StringScanner('test string');
|
699
|
+
* $s->pos; # -> 0
|
700
|
+
* $s->scanUntil /str/ # -> "test str"
|
701
|
+
* $s->pos; # -> 8
|
702
|
+
* $s->terminate(); # -> #<StringScanner fin>
|
703
|
+
* $s->pos; # -> 11
|
704
|
+
* @endcode
|
705
|
+
*
|
706
|
+
* @return int
|
707
|
+
*/
|
708
|
+
public function getPos() {
|
709
|
+
return $this->_curr;
|
710
|
+
}
|
711
|
+
|
712
|
+
/**
|
713
|
+
* Set the byte position of the scan pointer.
|
714
|
+
* @code
|
715
|
+
* $s = new StringScanner('test string');
|
716
|
+
* $s->pos = 7 # -> 7
|
717
|
+
* $s->rest; # -> "ring"
|
718
|
+
* @endcode
|
719
|
+
*
|
720
|
+
* @param int $i
|
721
|
+
* @return int The new position
|
722
|
+
*/
|
723
|
+
public function setPointer($i)
|
724
|
+
{
|
725
|
+
if ($i < 0)
|
726
|
+
$i += $this->_restSize;
|
727
|
+
|
728
|
+
if ($i < 0 || $i > $this->_restSize)
|
729
|
+
throw new Exception("Index out of range.");
|
730
|
+
|
731
|
+
$this->_curr = $i;
|
732
|
+
|
733
|
+
return $i;
|
734
|
+
}
|
735
|
+
|
736
|
+
/**
|
737
|
+
* Same as {@link setPointer()}
|
738
|
+
* Set the byte position of the scan pointer.
|
739
|
+
* @code
|
740
|
+
* $s = new StringScanner('test string');
|
741
|
+
* $s->pos = 7 # -> 7
|
742
|
+
* $s->rest; # -> "ring"
|
743
|
+
* @endcode
|
744
|
+
*
|
745
|
+
* @param int $i
|
746
|
+
* @return int The new position
|
747
|
+
*/
|
748
|
+
public function setPos($i) {
|
749
|
+
return $this->setPointer($i);
|
750
|
+
}
|
751
|
+
|
752
|
+
/**
|
753
|
+
* Return the <i><b>post</b>-match</i> (in the regular expression sense) of the last scan.
|
754
|
+
* @code
|
755
|
+
* $s = new StringScanner('test string');
|
756
|
+
* $s->scan('/\w+/'); # -> "test"
|
757
|
+
* $s->scan('/\s+/'); # -> " "
|
758
|
+
* $s->preMatch; # -> "test"
|
759
|
+
* $s->postMatch; # -> "string"
|
760
|
+
* @endcode
|
761
|
+
*
|
762
|
+
* @return string
|
763
|
+
*/
|
764
|
+
public function getPostMatch()
|
765
|
+
{
|
766
|
+
if(!isset($this->_matches[0]))
|
767
|
+
return null;
|
768
|
+
|
769
|
+
return mb_substr($this->_string, $this->_lastMatchEnd, $this->_size, $this->_encoding);
|
770
|
+
}
|
771
|
+
|
772
|
+
/**
|
773
|
+
* Return the <i><b>pre</b>-match</i> (in the regular expression sense) of the last scan.
|
774
|
+
* @code
|
775
|
+
* $s = new StringScanner('test string');
|
776
|
+
* $s->scan('/\w+/'); # -> "test"
|
777
|
+
* $s->scan('/\s+/'); # -> " "
|
778
|
+
* $s->preMatch; # -> "test"
|
779
|
+
* $s->postMatch; # -> "string"
|
780
|
+
* @endcode
|
781
|
+
*
|
782
|
+
* @return string
|
783
|
+
*/
|
784
|
+
public function getPreMatch()
|
785
|
+
{
|
786
|
+
if(!isset($this->_matches[0]))
|
787
|
+
return null;
|
788
|
+
|
789
|
+
return mb_substr($this->_string, 0, $this->_lastMatchBeg, $this->_encoding);
|
790
|
+
}
|
791
|
+
|
792
|
+
/**
|
793
|
+
* Reset the scan pointer (index 0) and clear matching data.
|
794
|
+
*/
|
795
|
+
public function reset()
|
796
|
+
{
|
797
|
+
$this->_string_updated(false);
|
798
|
+
}
|
799
|
+
|
800
|
+
/**
|
801
|
+
* Returns the "rest" of the string (i.e. everything after the scan pointer).
|
802
|
+
* If there is no more data (eos? = true), it returns <tt>""</tt>.
|
803
|
+
*
|
804
|
+
* @return string
|
805
|
+
*/
|
806
|
+
public function getRest()
|
807
|
+
{
|
808
|
+
return $this->_rest;
|
809
|
+
}
|
810
|
+
|
811
|
+
/**
|
812
|
+
* $s->restSize() is equivalent to mb_strlen($s->rest)
|
813
|
+
*/
|
814
|
+
public function restSize() {
|
815
|
+
return $this->_restSize;
|
816
|
+
}
|
817
|
+
|
818
|
+
/**
|
819
|
+
* Tries to match with $pattern at the current position. If there's a match,
|
820
|
+
* the scanner advances the scan @mlink{$pointer} and returns the matched string.
|
821
|
+
* Otherwise, the scanner returns <pre>null</pre>.
|
822
|
+
* @code
|
823
|
+
* $s = new StringScanner('test string');
|
824
|
+
* echo $s->scan('/\w+/'); # -> "test"
|
825
|
+
* echo $s->scan('/\w+/'); # -> null
|
826
|
+
* echo $s->scan('/\s+/'); # -> " "
|
827
|
+
* echo $s->scan('/\w+/'); # -> "string"
|
828
|
+
* echo $s->scan('/./'); # -> null
|
829
|
+
* @endcode
|
830
|
+
*
|
831
|
+
* @param string $pattern
|
832
|
+
*/
|
833
|
+
public function scan($pattern)
|
834
|
+
{
|
835
|
+
return $this->doScan($pattern, true, true, true);
|
836
|
+
}
|
837
|
+
|
838
|
+
/**
|
839
|
+
* Tests whether the given +pattern+ is matched from the current scan pointer.
|
840
|
+
* Advances the scan pointer if +advance_pointer_p+ is true.
|
841
|
+
* Returns the matched string if +return_string_p+ is true.
|
842
|
+
* The match register is affected.
|
843
|
+
*
|
844
|
+
* "full" means "#scan with full parameters".
|
845
|
+
*
|
846
|
+
* @todo Write test
|
847
|
+
* @param string $pattern The regular expression
|
848
|
+
* @param bool $advance_pointer Wheter to update the pointer or not
|
849
|
+
* @param bool $return_string Wheter to return the matched string or the position
|
850
|
+
* @return mixed Either the matched string (if $return_string is true) or the end position of the match
|
851
|
+
*/
|
852
|
+
public function scanFull($pattern, $advance_pointer, $return_string)
|
853
|
+
{
|
854
|
+
return $this->doScan($pattern, $advance_pointer, $return_string, true);
|
855
|
+
}
|
856
|
+
|
857
|
+
/**
|
858
|
+
* Scans the string _until_ the +pattern+ is matched. Returns the substring up
|
859
|
+
* to and including the end of the match, advancing the scan pointer to that
|
860
|
+
* location. If there is no match, +null+ is returned.
|
861
|
+
* @code
|
862
|
+
* $s = new StringScanner("Fri Dec 12 1975 14:39");
|
863
|
+
* $s->scanUntil('/1/'); # -> "Fri Dec 1"
|
864
|
+
* $s->preMatch(); # -> "Fri Dec "
|
865
|
+
* $s->scanUntil('/XYZ/'); # -> null
|
866
|
+
* @endcode
|
867
|
+
*
|
868
|
+
* @param string $pattern
|
869
|
+
* @return string The matched string
|
870
|
+
*/
|
871
|
+
public function scanUntil($pattern)
|
872
|
+
{
|
873
|
+
return $this->doScan($pattern, true, true, false);
|
874
|
+
}
|
875
|
+
|
876
|
+
/**
|
877
|
+
* Scans the string _until_ the $pattern is matched.
|
878
|
+
* Advances the scan pointer if $advance_pointer, otherwise not.
|
879
|
+
* Returns the matched string if $return_string is true, otherwise
|
880
|
+
* returns the number of bytes advanced.
|
881
|
+
* This method does affect the match register.
|
882
|
+
*
|
883
|
+
* @todo Write test
|
884
|
+
* @param string $pattern The regular expression
|
885
|
+
* @param bool $advance_pointer Wheter to update the pointer or not
|
886
|
+
* @param bool $return_string Wheter to return the matched string or the position
|
887
|
+
* @return mixed Either the matched string (if $return_string is true) or the end position of the match
|
888
|
+
*/
|
889
|
+
public function searchFull($pattern, $advance_pointer, $return_string)
|
890
|
+
{
|
891
|
+
return $this->doScan($pattern, $advance_pointer, $return_string, false);
|
892
|
+
}
|
893
|
+
|
894
|
+
/**
|
895
|
+
* Attempts to skip over the given +pattern+ beginning with the scan pointer.
|
896
|
+
* If it matches, the scan pointer is advanced to the end of the match, and the
|
897
|
+
* length of the match is returned. Otherwise, +null+ is returned.
|
898
|
+
*
|
899
|
+
* It's similar to #scan, but without returning the matched string.
|
900
|
+
* @code
|
901
|
+
* $s = new StringScanner('test string');
|
902
|
+
* echo $s->skip('/\w+/'); # -> 4
|
903
|
+
* echo $s->skip('/\w+/'); # -> null
|
904
|
+
* echo $s->skip('/\s+/'); # -> 1
|
905
|
+
* echo $s->skip('/\w+/'); # -> 6
|
906
|
+
* echo $s->skip('/./'); # -> null
|
907
|
+
* @endcode
|
908
|
+
*
|
909
|
+
* @param string $pattern
|
910
|
+
* @return int The new position
|
911
|
+
*/
|
912
|
+
public function skip($pattern)
|
913
|
+
{
|
914
|
+
return $this->doScan($pattern, true, false, true);
|
915
|
+
}
|
916
|
+
|
917
|
+
/**
|
918
|
+
* Advances the scan pointer until +pattern+ is matched and consumed. Returns
|
919
|
+
* the number of bytes advanced, or +null+ if no match was found.
|
920
|
+
*
|
921
|
+
* Look ahead to match +pattern+, and advance the scan pointer to the _end_
|
922
|
+
* of the match. Return the number of characters advanced, or +null+ if the
|
923
|
+
* match was unsuccessful.
|
924
|
+
*
|
925
|
+
* It's similar to #scanUntil, but without returning the intervening string.
|
926
|
+
*@code
|
927
|
+
* $s = new StringScanner("Fri Dec 12 1975 14:39");
|
928
|
+
* $s->skipUntil('/12/'); # -> 10
|
929
|
+
* @endcode
|
930
|
+
*
|
931
|
+
* @param string $pattern
|
932
|
+
* @return string The new pointer position
|
933
|
+
*/
|
934
|
+
public function skipUntil($pattern)
|
935
|
+
{
|
936
|
+
return $this->doScan($pattern, true, false, false);
|
937
|
+
}
|
938
|
+
|
939
|
+
/**
|
940
|
+
* Returns the string being scanned.
|
941
|
+
*
|
942
|
+
* @return string
|
943
|
+
*/
|
944
|
+
public function getString() {
|
945
|
+
return $this->_string;
|
946
|
+
}
|
947
|
+
|
948
|
+
/**
|
949
|
+
* Changes the string being scanned to +str+ and resets the scanner.
|
950
|
+
*
|
951
|
+
* @param string $str
|
952
|
+
* @return string $str
|
953
|
+
*/
|
954
|
+
public function setString($str) {
|
955
|
+
$this->_string = $str;
|
956
|
+
$this->reset();
|
957
|
+
return $str;
|
958
|
+
}
|
959
|
+
|
960
|
+
/**
|
961
|
+
* Set the scan pointer to the end of the string and clear matching data.
|
962
|
+
*/
|
963
|
+
public function terminate() {
|
964
|
+
$this->_curr = $this->_size;
|
965
|
+
$this->_clear_matched();
|
966
|
+
}
|
967
|
+
|
968
|
+
/**
|
969
|
+
* Set the scan pointer to the previous position. Only one previous position is
|
970
|
+
* remembered, and it changes with each scanning operation.
|
971
|
+
* @code
|
972
|
+
* $s = new StringScanner('test string');
|
973
|
+
* $s->scan('/\w+/'); # => "test"
|
974
|
+
* $s->unscan();
|
975
|
+
* $s->scan('/../'); # => "te"
|
976
|
+
* $s->scan('/\d/'); # => null
|
977
|
+
* $s->unscan(); # ScanError: unscan failed: previous match record not exist
|
978
|
+
* @endcode
|
979
|
+
*/
|
980
|
+
public function unscan()
|
981
|
+
{
|
982
|
+
if(!isset($this->_matches[0]))
|
983
|
+
throw new Exception("Unscan failed: previous match record not exist.");
|
984
|
+
|
985
|
+
$this->_curr = $this->_prev;
|
986
|
+
$this->_rest = mb_substr($this->_string, $this->_curr, $this->_size, $this->_encoding);
|
987
|
+
$this->_clear_matched();
|
988
|
+
}
|
989
|
+
}
|