]> git.lizzy.rs Git - rust.git/blob - src/libregex/re.rs
doc: remove incomplete sentence
[rust.git] / src / libregex / re.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 pub use self::NamesIter::*;
12 pub use self::Regex::*;
13
14 use std::borrow::IntoCow;
15 use std::collections::HashMap;
16 use std::fmt;
17 use std::str::CowString;
18
19 use compile::Program;
20 use parse;
21 use vm;
22 use vm::{CaptureLocs, MatchKind, Exists, Location, Submatches};
23
24 /// Escapes all regular expression meta characters in `text`.
25 ///
26 /// The string returned may be safely used as a literal in a regular
27 /// expression.
28 pub fn quote(text: &str) -> String {
29     let mut quoted = String::with_capacity(text.len());
30     for c in text.chars() {
31         if parse::is_punct(c) {
32             quoted.push('\\')
33         }
34         quoted.push(c);
35     }
36     quoted
37 }
38
39 /// Tests if the given regular expression matches somewhere in the text given.
40 ///
41 /// If there was a problem compiling the regular expression, an error is
42 /// returned.
43 ///
44 /// To find submatches, split or replace text, you'll need to compile an
45 /// expression first.
46 ///
47 /// Note that you should prefer the `regex!` macro when possible. For example,
48 /// `regex!("...").is_match("...")`.
49 pub fn is_match(regex: &str, text: &str) -> Result<bool, parse::Error> {
50     Regex::new(regex).map(|r| r.is_match(text))
51 }
52
53 /// A compiled regular expression
54 ///
55 /// It is represented as either a sequence of bytecode instructions (dynamic)
56 /// or as a specialized Rust function (native). It can be used to search, split
57 /// or replace text. All searching is done with an implicit `.*?` at the
58 /// beginning and end of an expression. To force an expression to match the
59 /// whole string (or a prefix or a suffix), you must use an anchor like `^` or
60 /// `$` (or `\A` and `\z`).
61 ///
62 /// While this crate will handle Unicode strings (whether in the regular
63 /// expression or in the search text), all positions returned are **byte
64 /// indices**. Every byte index is guaranteed to be at a Unicode code point
65 /// boundary.
66 ///
67 /// The lifetimes `'r` and `'t` in this crate correspond to the lifetime of a
68 /// compiled regular expression and text to search, respectively.
69 ///
70 /// The only methods that allocate new strings are the string replacement
71 /// methods. All other methods (searching and splitting) return borrowed
72 /// pointers into the string given.
73 ///
74 /// # Examples
75 ///
76 /// Find the location of a US phone number:
77 ///
78 /// ```rust
79 /// # use regex::Regex;
80 /// let re = match Regex::new("[0-9]{3}-[0-9]{3}-[0-9]{4}") {
81 ///     Ok(re) => re,
82 ///     Err(err) => panic!("{}", err),
83 /// };
84 /// assert_eq!(re.find("phone: 111-222-3333"), Some((7, 19)));
85 /// ```
86 ///
87 /// You can also use the `regex!` macro to compile a regular expression when
88 /// you compile your program:
89 ///
90 /// ```rust
91 /// #![feature(phase)]
92 /// extern crate regex;
93 /// #[phase(plugin)] extern crate regex_macros;
94 ///
95 /// fn main() {
96 ///     let re = regex!(r"\d+");
97 ///     assert_eq!(re.find("123 abc"), Some((0, 3)));
98 /// }
99 /// ```
100 ///
101 /// Given an incorrect regular expression, `regex!` will cause the Rust
102 /// compiler to produce a compile time error.
103 /// Note that `regex!` will compile the expression to native Rust code, which
104 /// makes it much faster when searching text.
105 /// More details about the `regex!` macro can be found in the `regex` crate
106 /// documentation.
107 #[deriving(Clone)]
108 pub enum Regex {
109     // The representation of `Regex` is exported to support the `regex!`
110     // syntax extension. Do not rely on it.
111     //
112     // See the comments for the `program` module in `lib.rs` for a more
113     // detailed explanation for what `regex!` requires.
114     #[doc(hidden)]
115     Dynamic(ExDynamic),
116     #[doc(hidden)]
117     Native(ExNative),
118 }
119
120 #[deriving(Clone)]
121 #[doc(hidden)]
122 pub struct ExDynamic {
123     original: String,
124     names: Vec<Option<String>>,
125     #[doc(hidden)]
126     pub prog: Program
127 }
128
129 #[doc(hidden)]
130 #[deriving(Copy)]
131 pub struct ExNative {
132     #[doc(hidden)]
133     pub original: &'static str,
134     #[doc(hidden)]
135     pub names: &'static &'static [Option<&'static str>],
136     #[doc(hidden)]
137     pub prog: fn(MatchKind, &str, uint, uint) -> Vec<Option<uint>>
138 }
139
140 impl Clone for ExNative {
141     fn clone(&self) -> ExNative {
142         *self
143     }
144 }
145
146 impl fmt::Show for Regex {
147     /// Shows the original regular expression.
148     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149         write!(f, "{}", self.as_str())
150     }
151 }
152
153 impl Regex {
154     /// Compiles a dynamic regular expression. Once compiled, it can be
155     /// used repeatedly to search, split or replace text in a string.
156     ///
157     /// When possible, you should prefer the `regex!` macro since it is
158     /// safer and always faster.
159     ///
160     /// If an invalid expression is given, then an error is returned.
161     pub fn new(re: &str) -> Result<Regex, parse::Error> {
162         let ast = try!(parse::parse(re));
163         let (prog, names) = Program::new(ast);
164         Ok(Dynamic(ExDynamic {
165             original: re.to_string(),
166             names: names,
167             prog: prog,
168         }))
169     }
170
171     /// Returns true if and only if the regex matches the string given.
172     ///
173     /// # Example
174     ///
175     /// Test if some text contains at least one word with exactly 13
176     /// characters:
177     ///
178     /// ```rust
179     /// # #![feature(phase)]
180     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
181     /// # fn main() {
182     /// let text = "I categorically deny having triskaidekaphobia.";
183     /// let matched = regex!(r"\b\w{13}\b").is_match(text);
184     /// assert!(matched);
185     /// # }
186     /// ```
187     pub fn is_match(&self, text: &str) -> bool {
188         has_match(&exec(self, Exists, text))
189     }
190
191     /// Returns the start and end byte range of the leftmost-first match in
192     /// `text`. If no match exists, then `None` is returned.
193     ///
194     /// Note that this should only be used if you want to discover the position
195     /// of the match. Testing the existence of a match is faster if you use
196     /// `is_match`.
197     ///
198     /// # Example
199     ///
200     /// Find the start and end location of the first word with exactly 13
201     /// characters:
202     ///
203     /// ```rust
204     /// # #![feature(phase)]
205     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
206     /// # fn main() {
207     /// let text = "I categorically deny having triskaidekaphobia.";
208     /// let pos = regex!(r"\b\w{13}\b").find(text);
209     /// assert_eq!(pos, Some((2, 15)));
210     /// # }
211     /// ```
212     pub fn find(&self, text: &str) -> Option<(uint, uint)> {
213         let caps = exec(self, Location, text);
214         if has_match(&caps) {
215             Some((caps[0].unwrap(), caps[1].unwrap()))
216         } else {
217             None
218         }
219     }
220
221     /// Returns an iterator for each successive non-overlapping match in
222     /// `text`, returning the start and end byte indices with respect to
223     /// `text`.
224     ///
225     /// # Example
226     ///
227     /// Find the start and end location of every word with exactly 13
228     /// characters:
229     ///
230     /// ```rust
231     /// # #![feature(phase)]
232     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
233     /// # fn main() {
234     /// let text = "Retroactively relinquishing remunerations is reprehensible.";
235     /// for pos in regex!(r"\b\w{13}\b").find_iter(text) {
236     ///     println!("{}", pos);
237     /// }
238     /// // Output:
239     /// // (0, 13)
240     /// // (14, 27)
241     /// // (28, 41)
242     /// // (45, 58)
243     /// # }
244     /// ```
245     pub fn find_iter<'r, 't>(&'r self, text: &'t str) -> FindMatches<'r, 't> {
246         FindMatches {
247             re: self,
248             search: text,
249             last_end: 0,
250             last_match: None,
251         }
252     }
253
254     /// Returns the capture groups corresponding to the leftmost-first
255     /// match in `text`. Capture group `0` always corresponds to the entire
256     /// match. If no match is found, then `None` is returned.
257     ///
258     /// You should only use `captures` if you need access to submatches.
259     /// Otherwise, `find` is faster for discovering the location of the overall
260     /// match.
261     ///
262     /// # Examples
263     ///
264     /// Say you have some text with movie names and their release years,
265     /// like "'Citizen Kane' (1941)". It'd be nice if we could search for text
266     /// looking like that, while also extracting the movie name and its release
267     /// year separately.
268     ///
269     /// ```rust
270     /// # #![feature(phase)]
271     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
272     /// # fn main() {
273     /// let re = regex!(r"'([^']+)'\s+\((\d{4})\)");
274     /// let text = "Not my favorite movie: 'Citizen Kane' (1941).";
275     /// let caps = re.captures(text).unwrap();
276     /// assert_eq!(caps.at(1), Some("Citizen Kane"));
277     /// assert_eq!(caps.at(2), Some("1941"));
278     /// assert_eq!(caps.at(0), Some("'Citizen Kane' (1941)"));
279     /// # }
280     /// ```
281     ///
282     /// Note that the full match is at capture group `0`. Each subsequent
283     /// capture group is indexed by the order of its opening `(`.
284     ///
285     /// We can make this example a bit clearer by using *named* capture groups:
286     ///
287     /// ```rust
288     /// # #![feature(phase)]
289     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
290     /// # fn main() {
291     /// let re = regex!(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)");
292     /// let text = "Not my favorite movie: 'Citizen Kane' (1941).";
293     /// let caps = re.captures(text).unwrap();
294     /// assert_eq!(caps.name("title"), Some("Citizen Kane"));
295     /// assert_eq!(caps.name("year"), Some("1941"));
296     /// assert_eq!(caps.at(0), Some("'Citizen Kane' (1941)"));
297     /// # }
298     /// ```
299     ///
300     /// Here we name the capture groups, which we can access with the `name`
301     /// method. Note that the named capture groups are still accessible with
302     /// `at`.
303     ///
304     /// The `0`th capture group is always unnamed, so it must always be
305     /// accessed with `at(0)`.
306     pub fn captures<'t>(&self, text: &'t str) -> Option<Captures<'t>> {
307         let caps = exec(self, Submatches, text);
308         Captures::new(self, text, caps)
309     }
310
311     /// Returns an iterator over all the non-overlapping capture groups matched
312     /// in `text`. This is operationally the same as `find_iter` (except it
313     /// yields information about submatches).
314     ///
315     /// # Example
316     ///
317     /// We can use this to find all movie titles and their release years in
318     /// some text, where the movie is formatted like "'Title' (xxxx)":
319     ///
320     /// ```rust
321     /// # #![feature(phase)]
322     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
323     /// # fn main() {
324     /// let re = regex!(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)");
325     /// let text = "'Citizen Kane' (1941), 'The Wizard of Oz' (1939), 'M' (1931).";
326     /// for caps in re.captures_iter(text) {
327     ///     println!("Movie: {}, Released: {}", caps.name("title"), caps.name("year"));
328     /// }
329     /// // Output:
330     /// // Movie: Citizen Kane, Released: 1941
331     /// // Movie: The Wizard of Oz, Released: 1939
332     /// // Movie: M, Released: 1931
333     /// # }
334     /// ```
335     pub fn captures_iter<'r, 't>(&'r self, text: &'t str)
336                                 -> FindCaptures<'r, 't> {
337         FindCaptures {
338             re: self,
339             search: text,
340             last_match: None,
341             last_end: 0,
342         }
343     }
344
345     /// Returns an iterator of substrings of `text` delimited by a match
346     /// of the regular expression.
347     /// Namely, each element of the iterator corresponds to text that *isn't*
348     /// matched by the regular expression.
349     ///
350     /// This method will *not* copy the text given.
351     ///
352     /// # Example
353     ///
354     /// To split a string delimited by arbitrary amounts of spaces or tabs:
355     ///
356     /// ```rust
357     /// # #![feature(phase)]
358     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
359     /// # fn main() {
360     /// let re = regex!(r"[ \t]+");
361     /// let fields: Vec<&str> = re.split("a b \t  c\td    e").collect();
362     /// assert_eq!(fields, vec!("a", "b", "c", "d", "e"));
363     /// # }
364     /// ```
365     pub fn split<'r, 't>(&'r self, text: &'t str) -> RegexSplits<'r, 't> {
366         RegexSplits {
367             finder: self.find_iter(text),
368             last: 0,
369         }
370     }
371
372     /// Returns an iterator of at most `limit` substrings of `text` delimited
373     /// by a match of the regular expression. (A `limit` of `0` will return no
374     /// substrings.)
375     /// Namely, each element of the iterator corresponds to text that *isn't*
376     /// matched by the regular expression.
377     /// The remainder of the string that is not split will be the last element
378     /// in the iterator.
379     ///
380     /// This method will *not* copy the text given.
381     ///
382     /// # Example
383     ///
384     /// Get the first two words in some text:
385     ///
386     /// ```rust
387     /// # #![feature(phase)]
388     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
389     /// # fn main() {
390     /// let re = regex!(r"\W+");
391     /// let fields: Vec<&str> = re.splitn("Hey! How are you?", 3).collect();
392     /// assert_eq!(fields, vec!("Hey", "How", "are you?"));
393     /// # }
394     /// ```
395     pub fn splitn<'r, 't>(&'r self, text: &'t str, limit: uint)
396                          -> RegexSplitsN<'r, 't> {
397         RegexSplitsN {
398             splits: self.split(text),
399             cur: 0,
400             limit: limit,
401         }
402     }
403
404     /// Replaces the leftmost-first match with the replacement provided.
405     /// The replacement can be a regular string (where `$N` and `$name` are
406     /// expanded to match capture groups) or a function that takes the matches'
407     /// `Captures` and returns the replaced string.
408     ///
409     /// If no match is found, then a copy of the string is returned unchanged.
410     ///
411     /// # Examples
412     ///
413     /// Note that this function is polymorphic with respect to the replacement.
414     /// In typical usage, this can just be a normal string:
415     ///
416     /// ```rust
417     /// # #![feature(phase)]
418     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
419     /// # fn main() {
420     /// let re = regex!("[^01]+");
421     /// assert_eq!(re.replace("1078910", ""), "1010");
422     /// # }
423     /// ```
424     ///
425     /// But anything satisfying the `Replacer` trait will work. For example,
426     /// a closure of type `|&Captures| -> String` provides direct access to the
427     /// captures corresponding to a match. This allows one to access
428     /// submatches easily:
429     ///
430     /// ```rust
431     /// # #![feature(phase)]
432     /// # #![feature(unboxed_closures)]
433     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
434     /// # use regex::Captures; fn main() {
435     /// let re = regex!(r"([^,\s]+),\s+(\S+)");
436     /// let result = re.replace("Springsteen, Bruce", |&: caps: &Captures| {
437     ///     format!("{} {}", caps.at(2).unwrap_or(""), caps.at(1).unwrap_or(""))
438     /// });
439     /// assert_eq!(result, "Bruce Springsteen");
440     /// # }
441     /// ```
442     ///
443     /// But this is a bit cumbersome to use all the time. Instead, a simple
444     /// syntax is supported that expands `$name` into the corresponding capture
445     /// group. Here's the last example, but using this expansion technique
446     /// with named capture groups:
447     ///
448     /// ```rust
449     /// # #![feature(phase)]
450     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
451     /// # fn main() {
452     /// let re = regex!(r"(?P<last>[^,\s]+),\s+(?P<first>\S+)");
453     /// let result = re.replace("Springsteen, Bruce", "$first $last");
454     /// assert_eq!(result, "Bruce Springsteen");
455     /// # }
456     /// ```
457     ///
458     /// Note that using `$2` instead of `$first` or `$1` instead of `$last`
459     /// would produce the same result. To write a literal `$` use `$$`.
460     ///
461     /// Finally, sometimes you just want to replace a literal string with no
462     /// submatch expansion. This can be done by wrapping a string with
463     /// `NoExpand`:
464     ///
465     /// ```rust
466     /// # #![feature(phase)]
467     /// # extern crate regex; #[phase(plugin)] extern crate regex_macros;
468     /// # fn main() {
469     /// use regex::NoExpand;
470     ///
471     /// let re = regex!(r"(?P<last>[^,\s]+),\s+(\S+)");
472     /// let result = re.replace("Springsteen, Bruce", NoExpand("$2 $last"));
473     /// assert_eq!(result, "$2 $last");
474     /// # }
475     /// ```
476     pub fn replace<R: Replacer>(&self, text: &str, rep: R) -> String {
477         self.replacen(text, 1, rep)
478     }
479
480     /// Replaces all non-overlapping matches in `text` with the
481     /// replacement provided. This is the same as calling `replacen` with
482     /// `limit` set to `0`.
483     ///
484     /// See the documentation for `replace` for details on how to access
485     /// submatches in the replacement string.
486     pub fn replace_all<R: Replacer>(&self, text: &str, rep: R) -> String {
487         self.replacen(text, 0, rep)
488     }
489
490     /// Replaces at most `limit` non-overlapping matches in `text` with the
491     /// replacement provided. If `limit` is 0, then all non-overlapping matches
492     /// are replaced.
493     ///
494     /// See the documentation for `replace` for details on how to access
495     /// submatches in the replacement string.
496     pub fn replacen<R: Replacer>
497                    (&self, text: &str, limit: uint, mut rep: R) -> String {
498         let mut new = String::with_capacity(text.len());
499         let mut last_match = 0u;
500
501         for (i, cap) in self.captures_iter(text).enumerate() {
502             // It'd be nicer to use the 'take' iterator instead, but it seemed
503             // awkward given that '0' => no limit.
504             if limit > 0 && i >= limit {
505                 break
506             }
507
508             let (s, e) = cap.pos(0).unwrap(); // captures only reports matches
509             new.push_str(text[last_match..s]);
510             new.push_str(rep.reg_replace(&cap)[]);
511             last_match = e;
512         }
513         new.push_str(text[last_match..text.len()]);
514         return new;
515     }
516
517     /// Returns the original string of this regex.
518     pub fn as_str<'a>(&'a self) -> &'a str {
519         match *self {
520             Dynamic(ExDynamic { ref original, .. }) => original[],
521             Native(ExNative { ref original, .. }) => original[],
522         }
523     }
524
525     #[doc(hidden)]
526     #[experimental]
527     pub fn names_iter<'a>(&'a self) -> NamesIter<'a> {
528         match *self {
529             Native(ref n) => NamesIterNative(n.names.iter()),
530             Dynamic(ref d) => NamesIterDynamic(d.names.iter())
531         }
532     }
533
534     fn names_len(&self) -> uint {
535         match *self {
536             Native(ref n) => n.names.len(),
537             Dynamic(ref d) => d.names.len()
538         }
539     }
540
541 }
542
543 #[deriving(Clone)]
544 pub enum NamesIter<'a> {
545     NamesIterNative(::std::slice::Iter<'a, Option<&'static str>>),
546     NamesIterDynamic(::std::slice::Iter<'a, Option<String>>)
547 }
548
549 impl<'a> Iterator for NamesIter<'a> {
550     type Item = Option<String>;
551
552     fn next(&mut self) -> Option<Option<String>> {
553         match *self {
554             NamesIterNative(ref mut i) => i.next().map(|x| x.map(|s| s.to_string())),
555             NamesIterDynamic(ref mut i) => i.next().map(|x| x.as_ref().map(|s| s.to_string())),
556         }
557     }
558 }
559
560 /// NoExpand indicates literal string replacement.
561 ///
562 /// It can be used with `replace` and `replace_all` to do a literal
563 /// string replacement without expanding `$name` to their corresponding
564 /// capture groups.
565 ///
566 /// `'r` is the lifetime of the literal text.
567 pub struct NoExpand<'t>(pub &'t str);
568
569 /// Replacer describes types that can be used to replace matches in a string.
570 pub trait Replacer {
571     /// Returns a possibly owned string that is used to replace the match
572     /// corresponding to the `caps` capture group.
573     ///
574     /// The `'a` lifetime refers to the lifetime of a borrowed string when
575     /// a new owned string isn't needed (e.g., for `NoExpand`).
576     fn reg_replace<'a>(&'a mut self, caps: &Captures) -> CowString<'a>;
577 }
578
579 impl<'t> Replacer for NoExpand<'t> {
580     fn reg_replace<'a>(&'a mut self, _: &Captures) -> CowString<'a> {
581         let NoExpand(s) = *self;
582         s.into_cow()
583     }
584 }
585
586 impl<'t> Replacer for &'t str {
587     fn reg_replace<'a>(&'a mut self, caps: &Captures) -> CowString<'a> {
588         caps.expand(*self).into_cow()
589     }
590 }
591
592 impl<F> Replacer for F where F: FnMut(&Captures) -> String {
593     fn reg_replace<'a>(&'a mut self, caps: &Captures) -> CowString<'a> {
594         (*self)(caps).into_cow()
595     }
596 }
597
598 /// Yields all substrings delimited by a regular expression match.
599 ///
600 /// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
601 /// of the string being split.
602 #[deriving(Clone)]
603 pub struct RegexSplits<'r, 't> {
604     finder: FindMatches<'r, 't>,
605     last: uint,
606 }
607
608 impl<'r, 't> Iterator for RegexSplits<'r, 't> {
609     type Item = &'t str;
610
611     fn next(&mut self) -> Option<&'t str> {
612         let text = self.finder.search;
613         match self.finder.next() {
614             None => {
615                 if self.last >= text.len() {
616                     None
617                 } else {
618                     let s = text[self.last..text.len()];
619                     self.last = text.len();
620                     Some(s)
621                 }
622             }
623             Some((s, e)) => {
624                 let matched = text[self.last..s];
625                 self.last = e;
626                 Some(matched)
627             }
628         }
629     }
630 }
631
632 /// Yields at most `N` substrings delimited by a regular expression match.
633 ///
634 /// The last substring will be whatever remains after splitting.
635 ///
636 /// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
637 /// of the string being split.
638 #[deriving(Clone)]
639 pub struct RegexSplitsN<'r, 't> {
640     splits: RegexSplits<'r, 't>,
641     cur: uint,
642     limit: uint,
643 }
644
645 impl<'r, 't> Iterator for RegexSplitsN<'r, 't> {
646     type Item = &'t str;
647
648     fn next(&mut self) -> Option<&'t str> {
649         let text = self.splits.finder.search;
650         if self.cur >= self.limit {
651             None
652         } else {
653             self.cur += 1;
654             if self.cur >= self.limit {
655                 Some(text[self.splits.last..text.len()])
656             } else {
657                 self.splits.next()
658             }
659         }
660     }
661 }
662
663 /// Captures represents a group of captured strings for a single match.
664 ///
665 /// The 0th capture always corresponds to the entire match. Each subsequent
666 /// index corresponds to the next capture group in the regex.
667 /// If a capture group is named, then the matched string is *also* available
668 /// via the `name` method. (Note that the 0th capture is always unnamed and so
669 /// must be accessed with the `at` method.)
670 ///
671 /// Positions returned from a capture group are always byte indices.
672 ///
673 /// `'t` is the lifetime of the matched text.
674 pub struct Captures<'t> {
675     text: &'t str,
676     locs: CaptureLocs,
677     named: Option<HashMap<String, uint>>,
678 }
679
680 impl<'t> Captures<'t> {
681     #[allow(experimental)]
682     fn new(re: &Regex, search: &'t str, locs: CaptureLocs)
683           -> Option<Captures<'t>> {
684         if !has_match(&locs) {
685             return None
686         }
687
688         let named =
689             if re.names_len() == 0 {
690                 None
691             } else {
692                 let mut named = HashMap::new();
693                 for (i, name) in re.names_iter().enumerate() {
694                     match name {
695                         None => {},
696                         Some(name) => {
697                             named.insert(name, i);
698                         }
699                     }
700                 }
701                 Some(named)
702             };
703         Some(Captures {
704             text: search,
705             locs: locs,
706             named: named,
707         })
708     }
709
710     /// Returns the start and end positions of the Nth capture group.
711     /// Returns `None` if `i` is not a valid capture group or if the capture
712     /// group did not match anything.
713     /// The positions returned are *always* byte indices with respect to the
714     /// original string matched.
715     pub fn pos(&self, i: uint) -> Option<(uint, uint)> {
716         let (s, e) = (i * 2, i * 2 + 1);
717         if e >= self.locs.len() || self.locs[s].is_none() {
718             // VM guarantees that each pair of locations are both Some or None.
719             return None
720         }
721         Some((self.locs[s].unwrap(), self.locs[e].unwrap()))
722     }
723
724     /// Returns the matched string for the capture group `i`.  If `i` isn't
725     /// a valid capture group or didn't match anything, then `None` is
726     /// returned.
727     pub fn at(&self, i: uint) -> Option<&'t str> {
728         match self.pos(i) {
729             None => None,
730             Some((s, e)) => Some(self.text.slice(s, e))
731         }
732     }
733
734     /// Returns the matched string for the capture group named `name`.  If
735     /// `name` isn't a valid capture group or didn't match anything, then
736     /// `None` is returned.
737     pub fn name(&self, name: &str) -> Option<&'t str> {
738         match self.named {
739             None => None,
740             Some(ref h) => {
741                 match h.get(name) {
742                     None => None,
743                     Some(i) => self.at(*i),
744                 }
745             }
746         }
747     }
748
749     /// Creates an iterator of all the capture groups in order of appearance
750     /// in the regular expression.
751     pub fn iter(&'t self) -> SubCaptures<'t> {
752         SubCaptures { idx: 0, caps: self, }
753     }
754
755     /// Creates an iterator of all the capture group positions in order of
756     /// appearance in the regular expression. Positions are byte indices
757     /// in terms of the original string matched.
758     pub fn iter_pos(&'t self) -> SubCapturesPos<'t> {
759         SubCapturesPos { idx: 0, caps: self, }
760     }
761
762     /// Expands all instances of `$name` in `text` to the corresponding capture
763     /// group `name`.
764     ///
765     /// `name` may be an integer corresponding to the index of the
766     /// capture group (counted by order of opening parenthesis where `0` is the
767     /// entire match) or it can be a name (consisting of letters, digits or
768     /// underscores) corresponding to a named capture group.
769     ///
770     /// If `name` isn't a valid capture group (whether the name doesn't exist or
771     /// isn't a valid index), then it is replaced with the empty string.
772     ///
773     /// To write a literal `$` use `$$`.
774     pub fn expand(&self, text: &str) -> String {
775         // How evil can you get?
776         // FIXME: Don't use regexes for this. It's completely unnecessary.
777         let re = Regex::new(r"(^|[^$]|\b)\$(\w+)").unwrap();
778         let text = re.replace_all(text, |&mut: refs: &Captures| -> String {
779             let pre = refs.at(1).unwrap_or("");
780             let name = refs.at(2).unwrap_or("");
781             format!("{}{}", pre,
782                     match name.parse::<uint>() {
783                 None => self.name(name).unwrap_or("").to_string(),
784                 Some(i) => self.at(i).unwrap_or("").to_string(),
785             })
786         });
787         let re = Regex::new(r"\$\$").unwrap();
788         re.replace_all(text[], NoExpand("$"))
789     }
790
791     /// Returns the number of captured groups.
792     #[inline]
793     pub fn len(&self) -> uint { self.locs.len() / 2 }
794
795     /// Returns if there are no captured groups.
796     #[inline]
797     pub fn is_empty(&self) -> bool { self.len() == 0 }
798 }
799
800 /// An iterator over capture groups for a particular match of a regular
801 /// expression.
802 ///
803 /// `'t` is the lifetime of the matched text.
804 #[deriving(Clone)]
805 pub struct SubCaptures<'t> {
806     idx: uint,
807     caps: &'t Captures<'t>,
808 }
809
810 impl<'t> Iterator for SubCaptures<'t> {
811     type Item = &'t str;
812
813     fn next(&mut self) -> Option<&'t str> {
814         if self.idx < self.caps.len() {
815             self.idx += 1;
816             Some(self.caps.at(self.idx - 1).unwrap_or(""))
817         } else {
818             None
819         }
820     }
821 }
822
823 /// An iterator over capture group positions for a particular match of a
824 /// regular expression.
825 ///
826 /// Positions are byte indices in terms of the original string matched.
827 ///
828 /// `'t` is the lifetime of the matched text.
829 #[deriving(Clone)]
830 pub struct SubCapturesPos<'t> {
831     idx: uint,
832     caps: &'t Captures<'t>,
833 }
834
835 impl<'t> Iterator for SubCapturesPos<'t> {
836     type Item = Option<(uint, uint)>;
837
838     fn next(&mut self) -> Option<Option<(uint, uint)>> {
839         if self.idx < self.caps.len() {
840             self.idx += 1;
841             Some(self.caps.pos(self.idx - 1))
842         } else {
843             None
844         }
845     }
846 }
847
848 /// An iterator that yields all non-overlapping capture groups matching a
849 /// particular regular expression.
850 ///
851 /// The iterator stops when no more matches can be found.
852 ///
853 /// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
854 /// of the matched string.
855 #[deriving(Clone)]
856 pub struct FindCaptures<'r, 't> {
857     re: &'r Regex,
858     search: &'t str,
859     last_match: Option<uint>,
860     last_end: uint,
861 }
862
863 impl<'r, 't> Iterator for FindCaptures<'r, 't> {
864     type Item = Captures<'t>;
865
866     fn next(&mut self) -> Option<Captures<'t>> {
867         if self.last_end > self.search.len() {
868             return None
869         }
870
871         let caps = exec_slice(self.re, Submatches, self.search,
872                               self.last_end, self.search.len());
873         let (s, e) =
874             if !has_match(&caps) {
875                 return None
876             } else {
877                 (caps[0].unwrap(), caps[1].unwrap())
878             };
879
880         // Don't accept empty matches immediately following a match.
881         // i.e., no infinite loops please.
882         if e == s && Some(self.last_end) == self.last_match {
883             self.last_end += 1;
884             return self.next()
885         }
886         self.last_end = e;
887         self.last_match = Some(self.last_end);
888         Captures::new(self.re, self.search, caps)
889     }
890 }
891
892 /// An iterator over all non-overlapping matches for a particular string.
893 ///
894 /// The iterator yields a tuple of integers corresponding to the start and end
895 /// of the match. The indices are byte offsets. The iterator stops when no more
896 /// matches can be found.
897 ///
898 /// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
899 /// of the matched string.
900 #[deriving(Clone)]
901 pub struct FindMatches<'r, 't> {
902     re: &'r Regex,
903     search: &'t str,
904     last_match: Option<uint>,
905     last_end: uint,
906 }
907
908 impl<'r, 't> Iterator for FindMatches<'r, 't> {
909     type Item = (uint, uint);
910
911     fn next(&mut self) -> Option<(uint, uint)> {
912         if self.last_end > self.search.len() {
913             return None
914         }
915
916         let caps = exec_slice(self.re, Location, self.search,
917                               self.last_end, self.search.len());
918         let (s, e) =
919             if !has_match(&caps) {
920                 return None
921             } else {
922                 (caps[0].unwrap(), caps[1].unwrap())
923             };
924
925         // Don't accept empty matches immediately following a match.
926         // i.e., no infinite loops please.
927         if e == s && Some(self.last_end) == self.last_match {
928             self.last_end += 1;
929             return self.next()
930         }
931         self.last_end = e;
932         self.last_match = Some(self.last_end);
933         Some((s, e))
934     }
935 }
936
937 fn exec(re: &Regex, which: MatchKind, input: &str) -> CaptureLocs {
938     exec_slice(re, which, input, 0, input.len())
939 }
940
941 fn exec_slice(re: &Regex, which: MatchKind,
942               input: &str, s: uint, e: uint) -> CaptureLocs {
943     match *re {
944         Dynamic(ExDynamic { ref prog, .. }) => vm::run(which, prog, input, s, e),
945         Native(ExNative { ref prog, .. }) => (*prog)(which, input, s, e),
946     }
947 }
948
949 #[inline]
950 fn has_match(caps: &CaptureLocs) -> bool {
951     caps.len() >= 2 && caps[0].is_some() && caps[1].is_some()
952 }