Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regular expression that both includes and excludes certain strings in R

Tags:

regex

r

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:

  1. I like apples
  2. I really like apples
  3. I like apples and oranges

I want to get entries 1 and 2 back.

How could I go about using R to do this?

Thanks.

like image 850
janovak Avatar asked May 29 '14 21:05

janovak


People also ask

How do you exclude words in regex?

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.

What is ?! In regex?

Definition and Usage. The ?! n quantifier matches any string that is not followed by a specific string n.

Does * match everything in regex?

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.

What is difference [] and () in regex?

[] 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 .


3 Answers

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.*$
  1. The negative lookahead ensures we don't have orange
  2. We just match the string, so long as it contains 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:

  1. Against 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).
  2. Against 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.

like image 172
zx81 Avatar answered Sep 21 '22 03:09

zx81


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"
like image 35
David Arenburg Avatar answered Sep 21 '22 03:09

David Arenburg


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)]
like image 23
hwnd Avatar answered Sep 22 '22 03:09

hwnd