55 lines
1.3 KiB
Rust
55 lines
1.3 KiB
Rust
// Taken from: https://github.com/rust-lang/regex/issues/330#issuecomment-274058261
|
|
use regex::{CaptureMatches, Captures, Regex};
|
|
|
|
pub struct SplitCaptures<'r, 't> {
|
|
finder: CaptureMatches<'r, 't>,
|
|
text: &'t str,
|
|
last: usize,
|
|
caps: Option<Captures<'t>>,
|
|
}
|
|
|
|
impl<'r, 't> SplitCaptures<'r, 't> {
|
|
pub fn new(re: &'r Regex, text: &'t str) -> SplitCaptures<'r, 't> {
|
|
SplitCaptures {
|
|
finder: re.captures_iter(text),
|
|
text,
|
|
last: 0,
|
|
caps: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum SplitState<'t> {
|
|
Unmatched(&'t str),
|
|
Captured(Captures<'t>),
|
|
}
|
|
|
|
impl<'r, 't> Iterator for SplitCaptures<'r, 't> {
|
|
type Item = SplitState<'t>;
|
|
|
|
fn next(&mut self) -> Option<SplitState<'t>> {
|
|
if let Some(caps) = self.caps.take() {
|
|
return Some(SplitState::Captured(caps));
|
|
}
|
|
match self.finder.next() {
|
|
None => {
|
|
if self.last >= self.text.len() {
|
|
None
|
|
} else {
|
|
let s = &self.text[self.last..];
|
|
self.last = self.text.len();
|
|
Some(SplitState::Unmatched(s))
|
|
}
|
|
}
|
|
Some(caps) => {
|
|
let m = caps.get(0).unwrap();
|
|
let unmatched = &self.text[self.last..m.start()];
|
|
self.last = m.end();
|
|
self.caps = Some(caps);
|
|
Some(SplitState::Unmatched(unmatched))
|
|
}
|
|
}
|
|
}
|
|
}
|