1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
use std::iter; use super::{Regex, Region, OPTION_NONE}; impl Regex { /// Returns the capture groups corresponding to the leftmost-first match /// in text. Capture group `0` always corresponds to the entire match. /// If no match is found, then `None` is returned. /// /// # Panics /// /// This method may panic in the case of memory overflow during execution or /// other internal errors of Oniguruma engine. pub fn captures<'t>(&self, text: &'t str) -> Option<Captures<'t>> { let mut region = Region::new(); self.search_with_region(text, &mut region, OPTION_NONE) .unwrap() .map(|_| Captures { text: text, region: region }) } } /// Captures represents a group of captured strings for a single match. /// /// The 0th capture always corresponds to the entire match. Each subsequent /// index corresponds to the next capture group in the regex. Positions /// returned from a capture group are always byte indices. /// /// `'t` is the lifetime of the matched text. #[derive(Debug)] pub struct Captures<'t> { text: &'t str, region: Region } impl<'t> Captures<'t> { /// Returns the start and end positions of the Nth capture group. Returns /// `None` if i is not a valid capture group or if the capture group did /// not match anything. The positions returned are always byte indices with /// respect to the original string matched. pub fn pos(&self, pos: usize) -> Option<(usize, usize)> { self.region.pos(pos) } /// Returns the matched string for the capture group `i`. If `i` isn't /// a valid capture group or didn't match anything, then `None` is returned. pub fn at(&self, pos: usize) -> Option<&'t str> { self.pos(pos).map(|(beg, end)| &self.text[beg..end]) } /// Returns the number of captured groups. pub fn len(&self) -> usize { self.region.len() } /// Returns true if and only if there are no captured groups. pub fn is_empty(&self) -> bool { self.len() == 0 } /// Creates an iterator of all the capture groups in order of appearance in // the regular expression. pub fn iter(&'t self) -> SubCaptures<'t> { SubCaptures { idx: 0, caps: self } } /// Creates an iterator of all the capture group positions in order of /// appearance in the regular expression. Positions are byte indices in /// terms of the original string matched. pub fn iter_pos(&'t self) -> SubCapturesPos<'t> { SubCapturesPos { idx: 0, caps: self } } } /// An iterator over capture groups for a particular match of a regular /// expression. /// ///`'t` is the lifetime of the matched text. pub struct SubCaptures<'t> { idx: usize, caps: &'t Captures<'t> } impl<'t> iter::Iterator for SubCaptures<'t> { type Item = Option<&'t str>; fn next(&mut self) -> Option<Option<&'t str>> { if self.idx < self.caps.len() { self.idx += 1; Some(self.caps.at(self.idx - 1)) } else { None } } } /// An iterator over capture group positions for a particular match of /// a regular expression. /// /// Positions are byte indices in terms of the original /// string matched. `'t` is the lifetime of the matched text. pub struct SubCapturesPos<'t> { idx: usize, caps: &'t Captures<'t> } impl<'t> iter::Iterator for SubCapturesPos<'t> { type Item = Option<(usize, usize)>; fn next(&mut self) -> Option<Option<(usize, usize)>> { if self.idx < self.caps.len() { self.idx += 1; Some(self.caps.pos(self.idx - 1)) } else { None } } }