Q:

Use grepl to match certain words but only in specific contexts where other words must not occur

Assuming this is my data...
mydata<-data.frame(text=c("There are books.","Books are bad.", "I like to read books."))

...how would I, using grepl, match rows in which "book(s)" occur, but "bad" doesn't (i.e. rows 1 and 3, but not row 2)?
I tried something like that with a negative lookahead...
grepl("book(s)?.*?(?!\\bbad\\b)", mydata$text, perl=T, ignore.case=T)

...but that didn't work as it also matches the second row. I assume that is because as soon as "book(s)" get detected, it returns "TRUE" and doesn't bother about whether or not "bad" co-occurs.
EDIT: Just to add this as a condition: I don't know anything about the specific structure of the string and the location of books and bads, but let's just assume book(s) comes first. Example: "there are plenty of books, all of which are bad, but some I really like.".

A:

Using negative lookahead, we can do
grepl("^(?!.*bad).*books.*$", mydata$text, perl = TRUE)
#[1]  TRUE FALSE  TRUE

This ensures that bad is not present in mydata$text before checking for books.

