support regex searches

This commit is contained in:
Damien Elmes 2020-03-21 12:00:48 +10:00
parent 2dc1b5c982
commit d1ebdbdcce
2 changed files with 22 additions and 4 deletions

View file

@ -5,7 +5,7 @@ use crate::err::{AnkiError, Result};
use crate::types::ObjID;
use nom::branch::alt;
use nom::bytes::complete::{escaped, is_not, tag, take_while1};
use nom::character::complete::{char, one_of};
use nom::character::complete::{anychar, char, one_of};
use nom::character::is_digit;
use nom::combinator::{all_consuming, map, map_res};
use nom::sequence::{delimited, preceded, tuple};
@ -77,6 +77,7 @@ pub(super) enum SearchNode<'a> {
kind: PropertyKind,
},
WholeCollection,
Regex(Cow<'a, str>),
}
#[derive(Debug, PartialEq)]
@ -235,9 +236,8 @@ fn quoted_term_str(s: &str) -> IResult<&str, &str> {
}
/// Quoted text, terminated by a non-escaped double quote
/// Can escape %, _, " and \
fn quoted_term_inner(s: &str) -> IResult<&str, &str> {
escaped(is_not(r#""\"#), '\\', one_of(r#""\%_"#))(s)
escaped(is_not(r#""\"#), '\\', anychar)(s)
}
/// eg deck:"foo bar" - quotes must come after the :
@ -270,7 +270,7 @@ fn search_node_for_text_with_argument<'a>(
"rated" => parse_rated(val.as_ref())?,
"dupes" => parse_dupes(val.as_ref())?,
"prop" => parse_prop(val.as_ref())?,
"re" => SearchNode::Regex(val),
// anything else is a field search
_ => SearchNode::SingleField {
field: key,
@ -432,6 +432,12 @@ mod test {
]
);
// any character should be escapable in quotes
assert_eq!(
parse(r#""re:\btest""#)?,
vec![Search(Regex(r"\btest".into()))]
);
assert_eq!(parse("added:3")?, vec![Search(AddedInDays(3))]);
assert_eq!(
parse("card:front")?,

View file

@ -80,6 +80,7 @@ impl SqlWriter<'_, '_> {
}
SearchNode::Property { operator, kind } => self.write_prop(operator, kind)?,
SearchNode::WholeCollection => write!(self.sql, "true").unwrap(),
SearchNode::Regex(re) => self.write_regex(re.as_ref()),
};
Ok(())
}
@ -334,6 +335,11 @@ impl SqlWriter<'_, '_> {
write!(self.sql, "c.id > {}", cutoff).unwrap();
Ok(())
}
fn write_regex(&mut self, word: &str) {
self.sql.push_str("n.flds regexp ?");
self.args.push(format!(r"(?i){}", word));
}
}
// Write a list of IDs as '(x,y,...)' into the provided string.
@ -537,6 +543,12 @@ mod test {
"(n.mid in (1581236385345,1581236385346,1581236385347,1581236385344))"
);
// regex
assert_eq!(
s(ctx, r"re:\bone"),
("(n.flds regexp ?)".into(), vec![r"(?i)\bone".into()])
);
Ok(())
})
.unwrap();