@@ -131,7 +131,7 @@ import java.util.regex.{ Pattern, Matcher }
131
131
* @author Martin Odersky
132
132
* @version 1.1, 29/01/2008
133
133
*
134
- * @param regex A string representing a regular expression
134
+ * @param pattern The compiled pattern
135
135
* @param groupNames A mapping from names to indices in capture groups
136
136
*
137
137
* @define replacementString
@@ -144,41 +144,67 @@ import java.util.regex.{ Pattern, Matcher }
144
144
* to automatically escape these characters.
145
145
*/
146
146
@ SerialVersionUID (- 2094783597747625537L )
147
- class Regex ( regex : String , groupNames : String * ) extends Serializable {
147
+ class Regex private [matching]( val pattern : Pattern , groupNames : String * ) extends Serializable {
148
148
outer =>
149
149
150
150
import Regex ._
151
151
152
- /** The compiled pattern */
153
- val pattern = Pattern .compile(regex)
152
+ /**
153
+ * @param regex A string representing a regular expression
154
+ * @param groupNames A mapping from names to indices in capture groups
155
+ */
156
+ def this (regex : String , groupNames : String * ) = this (Pattern .compile(regex), groupNames : _* )
154
157
155
- /** Tries to match target (whole match) and returns the matching subgroups.
156
- * if the pattern has no subgroups, then it returns an empty list on a
157
- * successful match.
158
- *
159
- * Note, however, that if some subgroup has not been matched, a `null` will
160
- * be returned for that subgroup.
158
+ /** Tries to match a [[java.lang.CharSequence ]].
159
+ * If the match succeeds, the result is a list of the matching
160
+ * groups (or a `null` element if a group did not match any input).
161
+ * If the pattern specifies no groups, then the result will be an empty list
162
+ * on a successful match.
161
163
*
164
+ * This method attempts to match the entire input by default; to find the next
165
+ * matching subsequence, use an unanchored Regex.
166
+
162
167
* For example:
163
168
*
164
169
* {{{
165
170
* val p1 = "ab*c".r
166
- * val p2 = "a(b*)c".r
167
- *
168
171
* val p1Matches = "abbbc" match {
169
172
* case p1() => true
170
173
* case _ => false
171
174
* }
172
- *
175
+ * val p2 = "a(b*)c".r
173
176
* val numberOfB = "abbbc" match {
174
177
* case p2(b) => Some(b.length)
175
178
* case _ => None
176
179
* }
180
+ * val p3 = "b*".r.unanchored
181
+ * val p3Matches = "abbbc" match {
182
+ * case p3() => true
183
+ * case _ => false
184
+ * }
177
185
* }}}
178
186
*
179
- * @param target The string to match
187
+ * @param s The string to match
180
188
* @return The matches
181
189
*/
190
+ def unapplySeq (s : CharSequence ): Option [Seq [String ]] = {
191
+ val m = pattern matcher s
192
+ if (runMatcher(m)) Some (1 to m.groupCount map m.group)
193
+ else None
194
+ }
195
+
196
+ /** Tries to match on a [[scala.util.matching.Regex.Match ]].
197
+ * A previously failed match results in None.
198
+ * If a successful match was made against the current pattern, then that result is used.
199
+ * Otherwise, this Regex is applied to the previously matched input,
200
+ * and the result of that match is used.
201
+ */
202
+ def unapplySeq (m : Match ): Option [Seq [String ]] =
203
+ if (m.matched == null ) None
204
+ else if (m.matcher.pattern == this .pattern) Some (1 to m.groupCount map m.group)
205
+ else unapplySeq(m.matched)
206
+
207
+ @ deprecated(" Extracting a match result from anything but a CharSequence or Match is deprecated" , " 2.10.0" )
182
208
def unapplySeq (target : Any ): Option [List [String ]] = target match {
183
209
case s : CharSequence =>
184
210
val m = pattern matcher s
@@ -187,6 +213,8 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
187
213
case m : Match => unapplySeq(m.matched)
188
214
case _ => None
189
215
}
216
+
217
+ // @see UnanchoredRegex
190
218
protected def runMatcher (m : Matcher ) = m.matches()
191
219
192
220
/** Return all matches of this regexp in given character sequence as a [[scala.util.matching.Regex.MatchIterator ]],
@@ -200,7 +228,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
200
228
* @return A [[scala.util.matching.Regex.MatchIterator ]] of all matches.
201
229
* @example {{{for (words <- """\w+""".r findAllIn "A simple example.") yield words}}}
202
230
*/
203
- def findAllIn (source : java.lang. CharSequence ) = new Regex .MatchIterator (source, this , groupNames)
231
+ def findAllIn (source : CharSequence ) = new Regex .MatchIterator (source, this , groupNames)
204
232
205
233
206
234
/** Return all matches of this regexp in given character sequence as a
@@ -210,7 +238,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
210
238
* @return A [[scala.collection.Iterator ]] of [[scala.util.matching.Regex.Match ]] for all matches.
211
239
* @example {{{for (words <- """\w+""".r findAllMatchIn "A simple example.") yield words.start}}}
212
240
*/
213
- def findAllMatchIn (source : java.lang. CharSequence ): Iterator [Match ] = {
241
+ def findAllMatchIn (source : CharSequence ): Iterator [Match ] = {
214
242
val matchIterator = findAllIn(source)
215
243
new Iterator [Match ] {
216
244
def hasNext = matchIterator.hasNext
@@ -228,7 +256,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
228
256
* @return An [[scala.Option ]] of the first matching string in the text.
229
257
* @example {{{"""\w+""".r findFirstIn "A simple example." foreach println // prints "A"}}}
230
258
*/
231
- def findFirstIn (source : java.lang. CharSequence ): Option [String ] = {
259
+ def findFirstIn (source : CharSequence ): Option [String ] = {
232
260
val m = pattern.matcher(source)
233
261
if (m.find) Some (m.group) else None
234
262
}
@@ -245,7 +273,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
245
273
* @return A [[scala.Option ]] of [[scala.util.matching.Regex.Match ]] of the first matching string in the text.
246
274
* @example {{{("""[a-z]""".r findFirstMatchIn "A simple example.") map (_.start) // returns Some(2), the index of the first match in the text}}}
247
275
*/
248
- def findFirstMatchIn (source : java.lang. CharSequence ): Option [Match ] = {
276
+ def findFirstMatchIn (source : CharSequence ): Option [Match ] = {
249
277
val m = pattern.matcher(source)
250
278
if (m.find) Some (new Match (source, m, groupNames)) else None
251
279
}
@@ -262,7 +290,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
262
290
* @return A [[scala.Option ]] of the matched prefix.
263
291
* @example {{{"""[a-z]""".r findPrefixOf "A simple example." // returns None, since the text does not begin with a lowercase letter}}}
264
292
*/
265
- def findPrefixOf (source : java.lang. CharSequence ): Option [String ] = {
293
+ def findPrefixOf (source : CharSequence ): Option [String ] = {
266
294
val m = pattern.matcher(source)
267
295
if (m.lookingAt) Some (m.group) else None
268
296
}
@@ -279,7 +307,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
279
307
* @return A [[scala.Option ]] of the [[scala.util.matching.Regex.Match ]] of the matched string.
280
308
* @example {{{"""\w+""".r findPrefixMatchOf "A simple example." map (_.after) // returns Some(" simple example.")}}}
281
309
*/
282
- def findPrefixMatchOf (source : java.lang. CharSequence ): Option [Match ] = {
310
+ def findPrefixMatchOf (source : CharSequence ): Option [Match ] = {
283
311
val m = pattern.matcher(source)
284
312
if (m.lookingAt) Some (new Match (source, m, groupNames)) else None
285
313
}
@@ -293,7 +321,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
293
321
* @return The resulting string
294
322
* @example {{{"""\d+""".r replaceAllIn ("July 15", "<NUMBER>") // returns "July <NUMBER>"}}}
295
323
*/
296
- def replaceAllIn (target : java.lang. CharSequence , replacement : String ): String = {
324
+ def replaceAllIn (target : CharSequence , replacement : String ): String = {
297
325
val m = pattern.matcher(target)
298
326
m.replaceAll(replacement)
299
327
}
@@ -316,7 +344,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
316
344
* @param replacer The function which maps a match to another string.
317
345
* @return The target string after replacements.
318
346
*/
319
- def replaceAllIn (target : java.lang. CharSequence , replacer : Match => String ): String = {
347
+ def replaceAllIn (target : CharSequence , replacer : Match => String ): String = {
320
348
val it = new Regex .MatchIterator (target, this , groupNames).replacementData
321
349
it foreach (md => it replace replacer(md))
322
350
it.replaced
@@ -343,7 +371,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
343
371
* @param replacer The function which optionally maps a match to another string.
344
372
* @return The target string after replacements.
345
373
*/
346
- def replaceSomeIn (target : java.lang. CharSequence , replacer : Match => Option [String ]): String = {
374
+ def replaceSomeIn (target : CharSequence , replacer : Match => Option [String ]): String = {
347
375
val it = new Regex .MatchIterator (target, this , groupNames).replacementData
348
376
for (matchdata <- it ; replacement <- replacer(matchdata))
349
377
it replace replacement
@@ -359,7 +387,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
359
387
* @param replacement The string that will replace the match
360
388
* @return The resulting string
361
389
*/
362
- def replaceFirstIn (target : java.lang. CharSequence , replacement : String ): String = {
390
+ def replaceFirstIn (target : CharSequence , replacement : String ): String = {
363
391
val m = pattern.matcher(target)
364
392
m.replaceFirst(replacement)
365
393
}
@@ -370,7 +398,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
370
398
* @return The array of strings computed by splitting the
371
399
* input around matches of this regexp
372
400
*/
373
- def split (toSplit : java.lang. CharSequence ): Array [String ] =
401
+ def split (toSplit : CharSequence ): Array [String ] =
374
402
pattern.split(toSplit)
375
403
376
404
/** Create a new Regex with the same pattern, but no requirement that
@@ -390,9 +418,11 @@ class Regex(regex: String, groupNames: String*) extends Serializable {
390
418
*
391
419
* @return The new unanchored regex
392
420
*/
393
- def unanchored : UnanchoredRegex = new Regex (regex , groupNames : _* ) with UnanchoredRegex { override def anchored = outer }
421
+ def unanchored : UnanchoredRegex = new Regex (pattern , groupNames : _* ) with UnanchoredRegex { override def anchored = outer }
394
422
def anchored : Regex = this
395
423
424
+ def regex : String = pattern.pattern
425
+
396
426
/** The string defining the regular expression */
397
427
override def toString = regex
398
428
}
@@ -421,7 +451,7 @@ object Regex {
421
451
trait MatchData {
422
452
423
453
/** The source from where the match originated */
424
- val source : java.lang. CharSequence
454
+ val source : CharSequence
425
455
426
456
/** The names of the groups, or some empty sequence if one defined */
427
457
val groupNames : Seq [String ]
@@ -459,25 +489,25 @@ object Regex {
459
489
460
490
/** The char sequence before first character of match,
461
491
* or `null` if nothing was matched */
462
- def before : java.lang. CharSequence =
492
+ def before : CharSequence =
463
493
if (start >= 0 ) source.subSequence(0 , start)
464
494
else null
465
495
466
496
/** The char sequence before first character of match in group `i`,
467
497
* or `null` if nothing was matched for that group */
468
- def before (i : Int ): java.lang. CharSequence =
498
+ def before (i : Int ): CharSequence =
469
499
if (start(i) >= 0 ) source.subSequence(0 , start(i))
470
500
else null
471
501
472
502
/** Returns char sequence after last character of match,
473
503
* or `null` if nothing was matched */
474
- def after : java.lang. CharSequence =
504
+ def after : CharSequence =
475
505
if (end >= 0 ) source.subSequence(end, source.length)
476
506
else null
477
507
478
508
/** The char sequence after last character of match in group `i`,
479
509
* or `null` if nothing was matched for that group */
480
- def after (i : Int ): java.lang. CharSequence =
510
+ def after (i : Int ): CharSequence =
481
511
if (end(i) >= 0 ) source.subSequence(end(i), source.length)
482
512
else null
483
513
@@ -501,8 +531,8 @@ object Regex {
501
531
502
532
/** Provides information about a succesful match.
503
533
*/
504
- class Match (val source : java.lang. CharSequence ,
505
- matcher : Matcher ,
534
+ class Match (val source : CharSequence ,
535
+ private [matching] val matcher : Matcher ,
506
536
val groupNames : Seq [String ]) extends MatchData {
507
537
508
538
/** The index of the first matched character */
@@ -563,7 +593,7 @@ object Regex {
563
593
564
594
/** A class to step through a sequence of regex matches
565
595
*/
566
- class MatchIterator (val source : java.lang. CharSequence , val regex : Regex , val groupNames : Seq [String ])
596
+ class MatchIterator (val source : CharSequence , val regex : Regex , val groupNames : Seq [String ])
567
597
extends AbstractIterator [String ] with Iterator [String ] with MatchData { self =>
568
598
569
599
protected [Regex ] val matcher = regex.pattern.matcher(source)
0 commit comments