web-dev-qa-db-fra.com

r- grepl pour trouver plusieurs chaînes existe

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

retournera true si l'un des instance ou percentage est présent.

Comment vais-je devenir vrai uniquement lorsque les deux termes sont présents.

6
toofrellik
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

Ce dernier travaille en recherchant:

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

Naturellement, si vous avez besoin de trouver une combinaison de plus de deux mots, cela deviendra assez compliqué. La solution mentionnée dans les commentaires serait alors plus facile à mettre en œuvre et à lire.

Une autre alternative qui pourrait être pertinente lors de la correspondance de plusieurs mots est d'utiliser une anticipation positive (peut être considérée comme une correspondance "non consommatrice"). Pour cela, vous devez activer 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)

De plus, si vous avez les motifs stockés dans un vecteur, vous pouvez condenser les expressions de manière significative, vous

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

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

Comme demandé dans les commentaires, si vous souhaitez faire correspondre les mots exacts, c'est-à-dire ne pas faire correspondre les sous-chaînes, nous pouvons spécifier les limites des mots en utilisant \\b. Par exemple:

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
15
AkselA

C'est ainsi que vous n'obtiendrez "VRAI" que si les deux termes se produisent dans un élément du vecteur "labelTest $ Text". Je pense que c'est la réponse exacte à la question et beaucoup plus courte que les autres solutions.

grepl("instance",labelTest$Text) & grepl("percentage",labelTest$Text)
1

Utilisez intersect et alimentez-le grep pour chaque mot:

library(data.table) #used for subsetting text vector below

vector_of_text[
  intersect(
    grep(vector_of_text , pattern = "pattern1"),
    grep(vector_of_text , pattern = "pattern2")
  )
]
0