Skip to content

Instantly share code, notes, and snippets.

@geotheory
Created October 19, 2020 14:43
Show Gist options
  • Save geotheory/df6da05a36a9d33fd05bdb1f1d700f9e to your computer and use it in GitHub Desktop.
Save geotheory/df6da05a36a9d33fd05bdb1f1d700f9e to your computer and use it in GitHub Desktop.
require(stringr)
bool_detect = function(x, qry, ignore_case = TRUE, print_call = FALSE){
ops = c(AND = '&', `&` = '&', OR = '|', `|` = '|', `(` = '(', `)` = ')') # boolean operators
# add spaces around parentheses;
qry = qry %>% str_trim %>% str_replace_all(fixed('('), '( ') %>% str_replace_all(fixed(')'), ' )') %>%
str_replace_all("'", '"') %>% # enforce double quotes
str_replace_all('(?<="[^ ]{0,100}) (?=[^ ]+")', '\u00A0') # sub spaces in quoted text for a unicode space
# split elements by ascii space character
comps = str_split(qry, '[ ]+')[[1]] %>% str_replace_all('\u00A0', ' ') %>% str_remove_all('"')
comp_ops = comps %in% names(ops) # identify operators from query terms
# construct string for a composite logical call to evaluate
to_negate = str_detect(comps[!comp_ops], '^-') # args to negate (NOT)
qry_neg = comps[!comp_ops] %>% str_replace('^-', '')
# build a str_detect command for each argument, negated as required
comps[!comp_ops] = paste0(c('','!')[to_negate+1], 'str_detect(x, regex("',
qry_neg, '", ignore_case=', ignore_case,'))')
comps[comp_ops] = ops[comps[comp_ops]] # convert AND/OR to R logical operators
qry_final = paste(comps, collapse = ' ') # reduce to single string
if(print_call) message(qry_final)
eval(parse(text = qry_final))
}
# Example usage
#' # simple AND
#' sentences[ bool_detect(sentences, 'cat AND dog', print_call=T) ]
#'
#' # simple OR
#' sentences[ bool_detect(sentences, 'cat OR dog', print_call=T) ]
#'
#' # nested OR
#' sentences[ bool_detect(sentences, '(corner OR tree) AND (cat OR dog)') ]
#'
#' # quoted phrases
#' sentences[ bool_detect(sentences, '"the big"') ]
#'
#' # Report hoe query is interpreted
#' x = bool_detect(sentences, 'cat OR dog', print_call=TRUE)
#'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment