Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R's grepl() to find multiple strings exists [duplicate]

Tags:

r

grepl

grepl("instance|percentage", labelTest$Text)

will return true if any one of instance or percentage is present.

How will I get true only when both the terms are present?

like image 318
toofrellik Avatar asked May 24 '17 08:05

toofrellik


People also ask

What does Grepl do in R?

The grepl() stands for “grep logical”. In R it is a built-in function that searches for matches of a string or string vector. The grepl() method takes a pattern and data and returns TRUE if a string contains the pattern, otherwise FALSE.

Can you double grep?

Grep is a powerful utility available by default on UNIX-based systems. The name stands for Global Regular Expression Print. By using the grep command, you can customize how the tool searches for a pattern or multiple patterns in this case. You can grep multiple strings in different files and directories.

What package is Grepl?

grepl() This is a function in the base package (e.g., it isn't part of dplyr ) that is part of the suite of Regular Expressions functions. grepl uses regular expressions to match patterns in character strings.


2 Answers

Text <- c("instance", "percentage", "n", 
          "instance percentage", "percentage instance")

grepl("instance|percentage", Text)
# TRUE  TRUE FALSE  TRUE  TRUE

grepl("instance.*percentage|percentage.*instance", Text)
# FALSE FALSE FALSE TRUE  TRUE

The latter one works by looking for:

('instance')(any character sequence)('percentage')  
OR  
('percentage')(any character sequence)('instance')

Naturally if you need to find any combination of more than two words, this will get pretty complicated. Then the solution mentioned in the comments would be easier to implement and read.

Another alternative that might be relevant when matching many words is to use positive look-ahead (can be thought of as a 'non-consuming' match). For this you have to activate perl regex.

# create a vector of word combinations
set.seed(1)
words <- c("instance", "percentage", "element",
           "character", "n", "o", "p")
Text2 <- replicate(10, paste(sample(words, 5), collapse=" "))

# grepl with multiple positive look-ahead
longperl <- grepl("(?=.*instance)(?=.*percentage)(?=.*element)(?=.*character)",
  Text2, perl=TRUE)

# this is equivalent to the solution proposed in the comments
longstrd <- grepl("instance", Text2) & 
          grepl("percentage", Text2) & 
             grepl("element", Text2) & 
           grepl("character", Text2)

# they produce identical results
identical(longperl, longstrd)

Furthermore, if you have the patterns stored in a vector you can condense the expressions significantly, giving you

pat <- c("instance", "percentage", "element", "character")

longperl <- grepl(paste0("(?=.*", pat, ")", collapse=""), Text2, perl=TRUE)
longstrd <- rowSums(sapply(pat, grepl, Text2) - 1L) == 0L

As asked for in the comments, if you want to match on exact words, i.e. not match on substrings, we can specify word boundaries using \\b. E.g:

tx <- c("cent element", "percentage element", "element cent", "element centimetre")

grepl("(?=.*\\bcent\\b)(?=.*element)", tx, perl=TRUE)
# TRUE FALSE  TRUE FALSE
grepl("element", tx) & grepl("\\bcent\\b", tx)
# TRUE FALSE  TRUE FALSE
like image 104
AkselA Avatar answered Oct 08 '22 19:10

AkselA


This is how you will get only "TRUE" if both terms do occur in an item of the vector "labelTest$Text". I think this is the exact answer to the question and much shorter than the other solutions.

grepl("instance",labelTest$Text) & grepl("percentage",labelTest$Text)
like image 23
Sebastian Geschonke Avatar answered Oct 08 '22 19:10

Sebastian Geschonke