I am trying to use R to parse through a number of entries. I have two requirements for the the entries I want back. I want all the entries that contain the word apple
but don't contain the word orange
.
For example:
I want to get entries 1 and 2 back.
How could I go about using R to do this?
Thanks.
To represent this, we use a similar expression that excludes specific characters using the square brackets and the ^ (hat). For example, the pattern [^abc] will match any single character except for the letters a, b, or c.
Definition and Usage. The ?! n quantifier matches any string that is not followed by a specific string n.
Throw in an * (asterisk), and it will match everything. Read more. \s (whitespace metacharacter) will match any whitespace character (space; tab; line break; ...), and \S (opposite of \s ) will match anything that is not a whitespace character.
[] denotes a character class. () denotes a capturing group. [a-z0-9] -- One character that is in the range of a-z OR 0-9. (a-z0-9) -- Explicit capture of a-z0-9 .
This regex is a bit smaller and much faster than the other regex versions (see comparison below). I don't have the tools to compare to David's double grepl
so if someone can compare the single grep
below vs the double grepl
we'll be able to know. The comparison must be done both for a success case and a failure case.
^(?!.*orange).*apple.*$
orange
apple
. No need for a lookahead there.Code Sample
grep("^(?!.*orange).*apple.*$", subject, perl=TRUE, value=TRUE);
Speed Comparison
@hwnd has now removed that double lookahead version, but according to RegexBuddy the speed difference remains:
I like apples and oranges
, the engine takes 22 steps to fail, vs. 143 for the double lookahead version ^(?=.*apple)((?!orange).)*$
and 22 steps for ^((?!.*orange).)*apple.*$
(equal there but wait for point 2). I really like apples
, the engine takes 64 steps to succeed, vs. 104 for the double lookahead version ^(?=.*apple)((?!orange).)*$
and 538 steps for ^((?!.*orange).)*apple.*$
.These numbers were provided by the RegexBuddy debugger.
Could do
temp <- c("I like apples", "I really like apples", "I like apples and oranges")
temp[grepl("apple", temp) & !grepl("orange", temp)]
## [1] "I like apples" "I really like apples"
Using a regular expression, you could do the following.
x <- c('I like apples', 'I really like apples',
'I like apples and oranges', 'I like oranges and apples',
'I really like oranges and apples but oranges more')
x[grepl('^((?!.*orange).)*apple.*$', x, perl=TRUE)]
# [1] "I like apples" "I really like apples"
The regular expression looks ahead to see if there's no character except a line break and no substring orange
and if so, then the dot .
will match any character except a line break as it is wrapped in a group, and repeated (0
or more times). Next we look for apple
and any character except a line break (0
or more times). Finally, the start and end of line anchors are in place to make sure the input is consumed.
UPDATE: You could use the following if performance is an issue.
x[grepl('^(?!.*orange).*$', x, perl=TRUE)]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With