Regex reading file contents

Hello!

I've recently started to learn Rust and I'm having some issues regarding regex. So i wanted my program to read the contents of the file and check if it matches the regex.

so heres the content of the file:

a = point ( 1 , 1 ) ;
b = point ( 2 , 2 ) ;
c = point ( 3 , 3 ) .

And here is my Rust program. sorry for the messy regex

use std::env;
use std::fs::File;
use std::io::prelude::*;
extern crate regex;
use regex::Regex;

fn main() -> std::io::Result<()>{
    let args: Vec<String> = env::args().collect();

	let reg : Regex = Regex::new(r"(?s)^[a-zA-z]+[[:space:]]*=[[:space:]]*point[[:space:]]*\([[:space:]]*[0-9]+[[:space:]]*,[[:space:]]*[0-9]+[[:space:]]*\)[[:space:]]*;\n[a-zA-z]+[[:space:]]*=[[:space:]]*point[[:space:]]*\([[:space:]]*[0-9]+[[:space:]]*,[[:space:]]*[0-9]+[[:space:]]*\)[[:space:]]*;\n[a-zA-z]+[[:space:]]*=[[:space:]]*point[[:space:]]*\([[:space:]]*[0-9]+[[:space:]]*,[[:space:]]*[0-9]+[[:space:]]*\)[[:space:]]*\.$").unwrap();
	

	let text = "a = point ( 1 , 1 ) ;
b = point ( 2 , 2 ) ;
c = point ( 3 , 3 ) .";
	
	
	
    let mut file = File::open(&args[1])?;   //specify filename in argument
    let mut contents = String::new();
	file.read_to_string(&mut contents)?;
		
		
	let contents_result = reg.is_match(&contents);
	let text_result = reg.is_match(text);
	
    if contents_result == true{
		println!("success");
	}
	else{
		println!("fail");
	}
	if text_result == true{
		println!("success");
	}
	else{
		println!("fail");
	}
	
	Ok(())
}

So the string inside text and the string inside the file is identical, But in the result matching, the text succeeded while the string from the file fails. Is there something im missing? Thank you for your time :slightly_smiling_face:

Probably the classic "you have an end-of-line character at the end of the file", isn't it?


Other than that, this regex is one heck of a beast. Why not process the input line-by-line and only write the regex for a single line? You could also simplify the regex and make it unicode-aware by using \w, \s, break it up into multiple lines and add comments using the (?x) option, like this (playground):

use regex::Regex;

fn main() {
	let text = "a = point ( 1 , 1 ) ;
b = point ( 2 , 2 ) ;
c = point ( 3 , 3 ) .";
	
	let rx = Regex::new(r"(?x)
	    ^\s*(?P<name>\w+)\s*= # name =
	    \s*point\s*\(         # point ()
	        \s*(?P<x>\d+)\s*, # X coordinate
	        \s*(?P<y>\d+)\s*  # Y coordinate
	    \)\s*[;\.]\s*$        # End of line").unwrap();
	
	for line in text.lines() {
	    if let Some(c) = rx.captures(line) {
	        println!("Name: {}, X = {}, Y = {}", &c["name"], &c["x"], &c["y"]);
	    }
	}
}
3 Likes

An alternative to regex is to use a parsing library like nom. It's more involved and does require learning a library, but it's a good option to keep in mind if you expect the file's contents to become more complicated in the future.

1 Like