2
\$\begingroup\$

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(())
}

Playground

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.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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(())
}
```
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.