Regular expression and captures in an if condition


I am processing text one line at a time using regular expressions. The structure of the line determines how it is processed.

A concrete example:

A line: "Sample rate: 48000" I want to store the sample rate and move on to the next line
A line: "xrun detected" I want to increment a counter and move on to the next line.

Coming from Perl I would say:

if($line =~ /Sample rate: (\d+)/){
  $sample_rate = $1;

I want to do that in Rust, but I cannot figure out how. I have achieved my goal, but without any elegance

I have the regular expression:
sample_rate_re: Regex::new(r"Samplerate: (\d+)").unwrap()

if sample_rate_re.captures(line).is_some() {
  let caps = sample_rate_re.captures(line).unwrap(); 
  let sample_rate_text: &str = caps.get(1).map_or("0", |m| -> &str m.as_str());
  sample_rate = sample_rate_text.parse().unwrap();

But I am using the regular expression twice.

I would like to say:

if  caps = sample_rate_re.captures(line).unwrap() {
  let sample_rate_text: &str = caps.get(1).map_or("0", |m| -> &str m.as_str());

but that is not valid Rust.

Is there a way to do this?

Why don't you use .map?

1 Like

In general, any time you find yourself writing is_some() followed by unwrap(), you should use if let instead:

if let Some(caps) = sample_rate_re.captures(line) {
  let sample_rate_text: &str = caps.get(1).map_or("0", |m| -> &str m.as_str());

Another simplification is to just use caps[1], because your capturing group is not conditional. It is required to match in order for the regex overall to match.

sample_rate = caps[1].parse().unwrap();

Although you shouldn't unwrap the result of parse, because the regex can match more than what can be parsed into an integer. (Your Perl program likely has the same problem.)