smarter match finding
This commit is contained in:
		
							parent
							
								
									4bcd7a2801
								
							
						
					
					
						commit
						066d927f3b
					
				
					 5 changed files with 125 additions and 41 deletions
				
			
		
							
								
								
									
										36
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
{
 | 
			
		||||
	// Use IntelliSense to learn about possible attributes.
 | 
			
		||||
	// Hover to view descriptions of existing attributes.
 | 
			
		||||
	// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
 | 
			
		||||
	"version": "0.2.0",
 | 
			
		||||
	"configurations": [
 | 
			
		||||
		{
 | 
			
		||||
			"type": "lldb",
 | 
			
		||||
			"request": "launch",
 | 
			
		||||
			"name": "Debug executable 'eyes'",
 | 
			
		||||
			"cargo": {
 | 
			
		||||
				"args": ["build", "--bin=eyes", "--package=eyes"],
 | 
			
		||||
				"filter": {
 | 
			
		||||
					"name": "eyes",
 | 
			
		||||
					"kind": "bin"
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			"args": [],
 | 
			
		||||
			"cwd": "${workspaceFolder}"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"type": "lldb",
 | 
			
		||||
			"request": "launch",
 | 
			
		||||
			"name": "Debug unit tests in executable 'eyes'",
 | 
			
		||||
			"cargo": {
 | 
			
		||||
				"args": ["test", "--no-run", "--bin=eyes", "--package=eyes"],
 | 
			
		||||
				"filter": {
 | 
			
		||||
					"name": "eyes",
 | 
			
		||||
					"kind": "bin"
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			"args": [],
 | 
			
		||||
			"cwd": "${workspaceFolder}"
 | 
			
		||||
		}
 | 
			
		||||
	]
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,5 +2,6 @@
 | 
			
		|||
name = "eyes"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2018"
 | 
			
		||||
license-file="LICENSE.txt"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										111
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								src/lib.rs
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,30 +1,42 @@
 | 
			
		|||
pub struct Parser<'a> {
 | 
			
		||||
    _input: &'a str,
 | 
			
		||||
    _pattern: &'a str,
 | 
			
		||||
    captures: Vec<&'a str>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> Parser<'a> {
 | 
			
		||||
    pub fn new(input: &'a str, pattern: &'a str) -> Self {
 | 
			
		||||
        let splits = pattern
 | 
			
		||||
    pub fn new(input: &'a str, template: &'a str) -> Self {
 | 
			
		||||
        let patterns = template
 | 
			
		||||
            .split("{}")
 | 
			
		||||
            .filter(|pat| pat != &"")
 | 
			
		||||
            .collect::<Vec<_>>();
 | 
			
		||||
        let mut captures = vec![input];
 | 
			
		||||
 | 
			
		||||
        for pat in splits {
 | 
			
		||||
            captures = captures
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|sub| sub.split(pat))
 | 
			
		||||
                .flatten()
 | 
			
		||||
                .collect();
 | 
			
		||||
        for (i, pat) in patterns.iter().enumerate() {
 | 
			
		||||
            let last = captures.pop().unwrap();
 | 
			
		||||
            let (mut left, mut right) = last.split_once(pat).unwrap();
 | 
			
		||||
 | 
			
		||||
            // if the right side of the split doesn't contain the pattern,
 | 
			
		||||
            // we don't have to check if we can expand the match
 | 
			
		||||
            if right.contains(pat) {
 | 
			
		||||
                let mut pattern_index = right.find(pat).unwrap() + left.len();
 | 
			
		||||
                let next_pattern_index = right.find(patterns[i + 1]).unwrap() + left.len();
 | 
			
		||||
 | 
			
		||||
                while next_pattern_index > pattern_index {
 | 
			
		||||
                    let (left_side, _) = input.split_at(pattern_index + 1);
 | 
			
		||||
                    left = left_side;
 | 
			
		||||
                    let (_, right_side) = input.split_at(pattern_index + 1 + pat.len());
 | 
			
		||||
                    right = right_side;
 | 
			
		||||
 | 
			
		||||
                    pattern_index = right.find(pat).unwrap_or(input.len()) + left.len();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if !left.is_empty() {
 | 
			
		||||
                captures.push(left);
 | 
			
		||||
            }
 | 
			
		||||
            captures.push(right);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Self {
 | 
			
		||||
            _input: input,
 | 
			
		||||
            _pattern: pattern,
 | 
			
		||||
            captures: captures[1..].to_vec(),
 | 
			
		||||
        }
 | 
			
		||||
        Self { captures }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn captures(&self) -> Vec<&'a str> {
 | 
			
		||||
| 
						 | 
				
			
			@ -36,15 +48,11 @@ impl<'a> Parser<'a> {
 | 
			
		|||
macro_rules! parse {
 | 
			
		||||
    ($input: expr, $pattern: tt, $($type:ty),*) => {
 | 
			
		||||
        {
 | 
			
		||||
            let mut parser = eyes::Parser::new($input, $pattern);
 | 
			
		||||
            let mut captures = parser.captures();
 | 
			
		||||
            captures.reverse();
 | 
			
		||||
            let parser = $crate::Parser::new($input, $pattern);
 | 
			
		||||
            let captures = parser.captures();
 | 
			
		||||
            let mut iter = captures.iter();
 | 
			
		||||
 | 
			
		||||
            (
 | 
			
		||||
            $({
 | 
			
		||||
                    captures.pop().unwrap().parse::<$type>().unwrap()
 | 
			
		||||
            },)*
 | 
			
		||||
            )
 | 
			
		||||
            ($(iter.next().unwrap().parse::<$type>().unwrap()),*)
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -53,15 +61,56 @@ macro_rules! parse {
 | 
			
		|||
macro_rules! try_parse {
 | 
			
		||||
    ($input: expr, $pattern: tt, $($type:ty),*) => {
 | 
			
		||||
        {
 | 
			
		||||
            let mut parser = eyes::Parser::new($input, $pattern);
 | 
			
		||||
            let mut captures = parser.captures();
 | 
			
		||||
            captures.reverse();
 | 
			
		||||
            let parser = $crate::Parser::new($input, $pattern);
 | 
			
		||||
            let captures = parser.captures();
 | 
			
		||||
            let mut iter = captures.iter();
 | 
			
		||||
 | 
			
		||||
            (
 | 
			
		||||
            $({
 | 
			
		||||
                    captures.pop().unwrap().parse::<$type>()
 | 
			
		||||
            },)*
 | 
			
		||||
            )
 | 
			
		||||
            ($(iter.next().unwrap().parse::<$type>()),*)
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn simple_test() {
 | 
			
		||||
        // Test where the patterns in the template are all different
 | 
			
		||||
        let input = "#lol @ 338,7643: 20.2x24.5";
 | 
			
		||||
        let template = "#{} @ {},{}: {}x{}";
 | 
			
		||||
 | 
			
		||||
        println!("input: '{}'", input);
 | 
			
		||||
        println!("pattern: '{}'", template);
 | 
			
		||||
 | 
			
		||||
        let (id, x, y, w, h) = parse!(input, template, String, isize, isize, f64, f64);
 | 
			
		||||
 | 
			
		||||
        println!("id: {:?}", id);
 | 
			
		||||
        println!("x: {:?}", x);
 | 
			
		||||
        println!("y: {:?}", y);
 | 
			
		||||
        println!("w: {:?}", w);
 | 
			
		||||
        println!("h: {:?}", h);
 | 
			
		||||
 | 
			
		||||
        assert_eq!((id.as_str(), x, y, w, h), ("lol", 338, 7643, 20.2, 24.5));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn tries_to_expand_correctly() {
 | 
			
		||||
        let input = "turn off 660,55 through 986,197";
 | 
			
		||||
        let template = "{} {},{} through {},{}";
 | 
			
		||||
 | 
			
		||||
        println!("input: '{}'", input);
 | 
			
		||||
        println!("pattern: '{}'", template);
 | 
			
		||||
 | 
			
		||||
        let (op, x1, y1, x2, y2) = try_parse!(input, template, String, usize, usize, usize, usize);
 | 
			
		||||
 | 
			
		||||
        println!("op: {:?}", op);
 | 
			
		||||
        println!("p1: {:?}", (&x1, &y1));
 | 
			
		||||
        println!("p2: {:?}", (&x2, &y2));
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            (op.unwrap().as_str(), x1, y1, x2, y2),
 | 
			
		||||
            ("turn off", Ok(660), Ok(55), Ok(986), Ok(197))
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/main.rs
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,17 +1,15 @@
 | 
			
		|||
use eyes::*;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let input = "#loll1 @ 338,764: 20x24";
 | 
			
		||||
    let pattern = "#{} @ {},{}: {}x{}";
 | 
			
		||||
    let input = "turn off 660,55 through 986,197";
 | 
			
		||||
    let template = "{} {},{} through {},{}";
 | 
			
		||||
 | 
			
		||||
    println!("input: {}", input);
 | 
			
		||||
    println!("pattern: {}", pattern);
 | 
			
		||||
    println!("input: '{}'", input);
 | 
			
		||||
    println!("pattern: '{}'", template);
 | 
			
		||||
 | 
			
		||||
    let (id, x, y, w, h) = parse!(input, pattern, String, f64, f32, usize, isize);
 | 
			
		||||
    let (op, x1, y1, x2, y2) = try_parse!(input, template, String, usize, usize, usize, usize);
 | 
			
		||||
 | 
			
		||||
    println!("id: {:?}", id);
 | 
			
		||||
    println!("x: {:?}", x);
 | 
			
		||||
    println!("y: {:?}", y);
 | 
			
		||||
    println!("w: {:?}", w);
 | 
			
		||||
    println!("h: {:?}", h);
 | 
			
		||||
    println!("op: {:?}", op);
 | 
			
		||||
    println!("p1: {:?}", (x1, y1));
 | 
			
		||||
    println!("p2: {:?}", (x2, y2));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue