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"
 | 
					name = "eyes"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
edition = "2018"
 | 
					edition = "2018"
 | 
				
			||||||
 | 
					license-file="LICENSE.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										109
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								src/lib.rs
									
									
									
									
									
								
							| 
						 | 
					@ -1,30 +1,42 @@
 | 
				
			||||||
pub struct Parser<'a> {
 | 
					pub struct Parser<'a> {
 | 
				
			||||||
    _input: &'a str,
 | 
					 | 
				
			||||||
    _pattern: &'a str,
 | 
					 | 
				
			||||||
    captures: Vec<&'a str>,
 | 
					    captures: Vec<&'a str>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    pub fn new(input: &'a str, pattern: &'a str) -> Self {
 | 
					    pub fn new(input: &'a str, template: &'a str) -> Self {
 | 
				
			||||||
        let splits = pattern
 | 
					        let patterns = template
 | 
				
			||||||
            .split("{}")
 | 
					            .split("{}")
 | 
				
			||||||
            .filter(|pat| pat != &"")
 | 
					            .filter(|pat| pat != &"")
 | 
				
			||||||
            .collect::<Vec<_>>();
 | 
					            .collect::<Vec<_>>();
 | 
				
			||||||
        let mut captures = vec![input];
 | 
					        let mut captures = vec![input];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for pat in splits {
 | 
					        for (i, pat) in patterns.iter().enumerate() {
 | 
				
			||||||
            captures = captures
 | 
					            let last = captures.pop().unwrap();
 | 
				
			||||||
                .iter()
 | 
					            let (mut left, mut right) = last.split_once(pat).unwrap();
 | 
				
			||||||
                .map(|sub| sub.split(pat))
 | 
					
 | 
				
			||||||
                .flatten()
 | 
					            // if the right side of the split doesn't contain the pattern,
 | 
				
			||||||
                .collect();
 | 
					            // 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();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Self {
 | 
					            if !left.is_empty() {
 | 
				
			||||||
            _input: input,
 | 
					                captures.push(left);
 | 
				
			||||||
            _pattern: pattern,
 | 
					 | 
				
			||||||
            captures: captures[1..].to_vec(),
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            captures.push(right);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Self { captures }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn captures(&self) -> Vec<&'a str> {
 | 
					    pub fn captures(&self) -> Vec<&'a str> {
 | 
				
			||||||
| 
						 | 
					@ -36,15 +48,11 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
macro_rules! parse {
 | 
					macro_rules! parse {
 | 
				
			||||||
    ($input: expr, $pattern: tt, $($type:ty),*) => {
 | 
					    ($input: expr, $pattern: tt, $($type:ty),*) => {
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            let mut parser = eyes::Parser::new($input, $pattern);
 | 
					            let parser = $crate::Parser::new($input, $pattern);
 | 
				
			||||||
            let mut captures = parser.captures();
 | 
					            let captures = parser.captures();
 | 
				
			||||||
            captures.reverse();
 | 
					            let mut iter = captures.iter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            (
 | 
					            ($(iter.next().unwrap().parse::<$type>().unwrap()),*)
 | 
				
			||||||
            $({
 | 
					 | 
				
			||||||
                    captures.pop().unwrap().parse::<$type>().unwrap()
 | 
					 | 
				
			||||||
            },)*
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -53,15 +61,56 @@ macro_rules! parse {
 | 
				
			||||||
macro_rules! try_parse {
 | 
					macro_rules! try_parse {
 | 
				
			||||||
    ($input: expr, $pattern: tt, $($type:ty),*) => {
 | 
					    ($input: expr, $pattern: tt, $($type:ty),*) => {
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            let mut parser = eyes::Parser::new($input, $pattern);
 | 
					            let parser = $crate::Parser::new($input, $pattern);
 | 
				
			||||||
            let mut captures = parser.captures();
 | 
					            let captures = parser.captures();
 | 
				
			||||||
            captures.reverse();
 | 
					            let mut iter = captures.iter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            (
 | 
					            ($(iter.next().unwrap().parse::<$type>()),*)
 | 
				
			||||||
            $({
 | 
					 | 
				
			||||||
                    captures.pop().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::*;
 | 
					use eyes::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    let input = "#loll1 @ 338,764: 20x24";
 | 
					    let input = "turn off 660,55 through 986,197";
 | 
				
			||||||
    let pattern = "#{} @ {},{}: {}x{}";
 | 
					    let template = "{} {},{} through {},{}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    println!("input: {}", input);
 | 
					    println!("input: '{}'", input);
 | 
				
			||||||
    println!("pattern: {}", pattern);
 | 
					    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!("op: {:?}", op);
 | 
				
			||||||
    println!("x: {:?}", x);
 | 
					    println!("p1: {:?}", (x1, y1));
 | 
				
			||||||
    println!("y: {:?}", y);
 | 
					    println!("p2: {:?}", (x2, y2));
 | 
				
			||||||
    println!("w: {:?}", w);
 | 
					 | 
				
			||||||
    println!("h: {:?}", h);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue