Function scout::refine
[−]
[src]
pub fn refine(re: &Regex, text: &str) -> Option<Choice>
Given a Regex
and a &str
, determine if is a valid Choice
.
If None
is returned it means that the text doesn't match with the Regex
, so it
is descarted.
This is the main algorithm to detect if a text matches against a set of chars, so lets explain it a little bit:
Imagine that you have the Regex based on the pattern:
use regex::Regex; let re = Regex::new("(?i)a.*?b.*?c").unwrap();
Which means: check if a string has an a
, then anything, then a b
, then anything and then
c
and be case insensitive, please.
Now imagine that you have the text:
let text = "a/a/b/c.rs"
We need to note that when doing a fuzzy search, we want the shortest possible match so we can narrow to the best possible match.
Now, returning to the example, if we run the regex against the string, it will match with this section:
let matching = "(a/a/b/c).rs" // ^ ^ // |-------| // match
But the best possible match would be:
let best_matching = "a/(a/b/c).rs" // ^ ^ // |-----| // match
How can we get the best match? By getting all the possible matches in a string.
The idea is that once we get a match, we cut the string where the match starts and then we try
this new string against the Regex
again. If it matches, then we have a shorter match. If not,
then we can't find any other match.
In the example, we would do the following:
- We run
"a/a/b/c.rs"
against(?i)a.*?b.*?c
and we get the match(a/a/b/c).rs
. - We remove the starting char of the match, in this case the first
a
, index0
. This gives us the string"/a/b/c.rs"
. - We run
"/a/b/c.rs"
against(?i)a.*?b.*?c
and we get the match/(a/b/c).rs
. - We remove the starting char of the match, in this case the second
a
, index2
. This gives us the string "/b/c.rs
". - We run
"/b/c.rs"
against(?i)a.*?b.*?c
and we don't get any match. This is the end of the checks. - Now we have two matches, two possible choices. We select the shortest which is the one
matching
"a/(a/b/c).rs"
.
The refine
function does all of this for us.
Example
extern crate regex; extern crate scout; use regex::Regex; use scout; let re = Regex::new("(?i)a.*?b.*?c").unwrap(); let text = "a/a/b/c.rs"; match scout::refine(&re, text) { Some(choice) => { let debug = format!("{} ({}, {})", choice.to_string(), choice.start(), choice.end()); assert_eq!("a/a/b/c.rs (2, 7)", debug); } None => panic!("It should match") };