I am trying to replicate the -A
and -B
argument functionality from GNU grep
in Rust. This prints out lines of text before and after a matched line read from a file or stdin. Example:
$ printf '1\n2\n3\nfoo\n4\n5\n6\n7\nfoo\n8\n9' | grep -A 1 -B 1 foo
3
foo
4
--
--
7
foo
8
My desired output would return n
lines preceding and/or following a pattern match.
Using just stdin as an example, the simple case of just returning the matched line is easy to implement like this:
use std::io::{self, BufRead, BufReader, Result};
fn main() {
for line in BufReader::new(io::stdin()).lines() {
match line {
Ok(l) => {
if l.contains("foo"){
println!("{}", l);
}
}
Err(e) => println!("error parsing line: {:?}", e),
}
}
}
output:
$ printf '1\n2\n3\nfoo\n4\n5\n6\n7\nfoo\n8\n9' | cargo run
foo
foo
However, returning the surrounding lines in an iterator like this does not seem possible, since the previous lines are no longer accessible upon each iteration of the loop.
I saw the Windows
type, but it only works on a slice.
This sliding_windows
crate appears to be the kind of functionality I want, but I cannot figure out how to get it to work with an iterator over lines from a file.
I also looked at itertools
but did not see any kind of window iterator function that did this.
Before I get too deep in rolling my own form of line-buffer object in order to cache n
previously seen lines (maybe some kind of ring buffer?), I was hoping that there might already be some method available in Rust that could easily accomplish this.