I am completely new to rust. My first rust code is simple text filter application for parsing log file and accumulating some information. Here is my code:
//use std::io::{self, Read};
use std::io::{self};
use regex::Regex;
fn main() -> io::Result<()> {
let re_str = concat!(
r"^\s+(?P<qrw1>\d+)\|(?P<qrw2>\d+)",//qrw 0|0
r"\s+(?P<arw1>\d+)\|(?P<arw2>\d+)",//arw 34|118
);
let re = Regex::new(re_str).unwrap();
//let mut buffer = String::new();
//io::stdin().read_to_string(&mut buffer)?;
let buffer = " 0|1 2|3\n 4|5 6|7\n 8|9 10|11\n";
let mut lines_skipped = 0;
let mut m_qrw1:i32 = 0;
let mut m_qrw2:i32 = 0;
let mut m_arw1:i32 = 0;
let mut m_arw2:i32 = 0;
for line in buffer.lines() {
match re.captures(line) {
Some(caps) => {
// I would like to shorten these long lines =>
let qrw1 = caps.name("qrw1").unwrap().as_str().parse::<i32>().unwrap();
let qrw2 = caps.name("qrw2").unwrap().as_str().parse::<i32>().unwrap();
let arw1 = caps.name("arw1").unwrap().as_str().parse::<i32>().unwrap();
let arw2 = caps.name("arw2").unwrap().as_str().parse::<i32>().unwrap();
if qrw1 > m_qrw1 {m_qrw1 = qrw1}
if qrw2 > m_qrw2 {m_qrw2 = qrw2}
if arw1 > m_arw1 {m_arw1 = arw1}
if arw2 > m_arw2 {m_arw2 = arw2}
}
None => {
lines_skipped = lines_skipped + 1;
}
}
}
println!("max qrw1: {:.2}", m_qrw1);
println!("max qrw2: {:.2}", m_qrw2);
println!("max arw1: {:.2}", m_arw1);
println!("max arw2: {:.2}", m_arw2);
Ok(())
}
This works as expected, but I think those long chained calls which I created to get integer values of regex named capture groups are a bit ugly. How do I make them shorter/more in idiomatic rust style? I've got an advice to use ? operator instead of unwrap
calls but I'm not sure how to apply it in this case.
1 Answer 1
regex::Captures
provides a handy implementation of Index<&str>
. This lets you pull named matches out with caps[name]
. Combine that with a few std
APIs and you can write the same code like this:
use regex::Regex;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let re = Regex::new(concat!(
r"^\s+(?P<qrw1>\d+)\|(?P<qrw2>\d+)",
r"\s+(?P<arw1>\d+)\|(?P<arw2>\d+)",
))
.unwrap();
let names = ["qrw1", "qrw2", "arw1", "arw2"];
let buffer = " 0|1 2|3\n 4|5 6|7\n 8|9 10|11\n";
let mut maximums = [0i32; 4];
for caps in buffer.lines().filter_map(|line| re.captures(line)) {
for (&name, max) in names.iter().zip(&mut maximums) {
*max = std::cmp::max(*max, caps[name].parse()?);
}
}
for (&name, max) in names.iter().zip(&maximums) {
println!("max {}: {:.2}", name, max);
}
Ok(())
}
```