web-dev-qa-db-fra.com

Faire correspondre plusieurs modèles

Je veux voir si "001" ou "100" ou "000" apparaît dans une chaîne de 4 caractères de 0 et 1. Par exemple, une chaîne de 4 caractères pourrait être de type "1100" ou "0010" ou "1001" ou "1111". Comment faire correspondre plusieurs chaînes d'une chaîne avec une seule commande? 

Je sais que grep pourrait être utilisé pour la recherche de motif, mais en utilisant grep, je ne peux vérifier qu'une chaîne à la fois. Je veux savoir si plusieurs chaînes peuvent être utilisées avec une autre commande ou avec grep lui-même.

20
Narayani

Oui, vous pouvez. Le | dans un modèle grep a la même signification que or. Vous pouvez donc tester votre modèle en utilisant "001|100|000" en tant que votre modèle. Dans le même temps, grep est vectorisé, donc tout cela peut être fait en une seule étape: 

x <- c("1100", "0010", "1001", "1111")
pattern <- "001|100|000"

grep(pattern, x)
[1] 1 2 3

Ceci retourne un index de vos vecteurs contenant le motif correspondant (dans ce cas, les trois premiers.)

Il est parfois plus pratique d’avoir un vecteur logique qui vous indique quels éléments de votre vecteur ont été mis en correspondance. Ensuite, vous pouvez utiliser grepl:

grepl(pattern, x)
[1]  TRUE  TRUE  TRUE FALSE

Voir ?regex pour obtenir de l'aide sur les expressions régulières dans R.


Edit: Pour éviter de créer un motif manuellement, nous pouvons utiliser paste:

myValues <- c("001", "100", "000")
pattern <- paste(myValues, collapse = "|")
40
Andrie

Voici une solution utilisant le paquet stringr

require(stringr)
mylist = c("1100", "0010", "1001", "1111")
str_locate(mylist, "000|001|100")
7
Ramnath

Utilisez l'argument -e pour ajouter des motifs supplémentaires:

echo '1100' | grep -e '001' -e '110' -e '101'
3
Patrick Dignan

Vous pouvez également utiliser l'opérateur %like% de la bibliothèque data.table.

library(data.table)

# input
  x <- c("1100", "0010", "1001", "1111")
  pattern <- "001|100|000"

# check for pattern
  x %like% pattern

> [1]  TRUE  TRUE  TRUE FALSE
1
rafa.pereira

Si vous voulez un vecteur logique, vous devriez vérifier la fonction stri_detect à partir du paquet stringi. Dans votre cas, le motif est regex, utilisez donc celui-ci:

stri_detect_regex(x, pattern)
## [1]  TRUE  TRUE  TRUE FALSE

Et quelques repères:

require(microbenchmark)
test <- stri_paste(stri_Rand_strings(100000, 4, "[0-1]"))
head(test)
## [1] "0001" "1111" "1101" "1101" "1110" "0110"
microbenchmark(stri_detect_regex(test, pattern), grepl(pattern, test))
Unit: milliseconds
                             expr      min       lq     mean   median       uq      max neval
 stri_detect_regex(test, pattern) 29.67405 30.30656 31.61175 30.93748 33.14948 35.90658   100
             grepl(pattern, test) 36.72723 37.71329 40.08595 40.01104 41.57586 48.63421   100
1
bartektartanus

Désolé de faire une réponse supplémentaire, mais c'est trop de lignes pour un commentaire. 

Je voulais simplement rappeler que le nombre d'éléments pouvant être collés ensemble via paste(..., collapse = "|") pour être utilisés comme un seul motif correspondant est limité - voir ci-dessous. Peut-être que quelqu'un peut dire où se trouve exactement la limite? Certes, le nombre pourrait ne pas être réaliste, mais en fonction de la tâche à exécuter, il ne devrait pas être totalement exclu de nos considérations.

Pour un très grand nombre d'éléments, une boucle serait nécessaire pour vérifier chaque élément du motif.

set.seed(0)
samplefun <- function(n, x, collapse){
  paste(sample(x, n, replace=TRUE), collapse=collapse)
}

words <- sapply(rpois(10000000, 8) + 1, samplefun, letters, '')
text <- sapply(rpois(1000, 5) + 1, samplefun, words, ' ')

#since execution takes a while, I have commented out the following lines

#result <- grepl(paste(words, collapse = "|"), text)

# Error in grepl(pattern, text) : 
#   invalid regular expression 
# 'wljtpgjqtnw|twiv|jphmer|mcemahvlsjxr|grehqfgldkgfu|
# ...

#result <- stringi::stri_detect_regex(text, paste(words, collapse = "|"))

# Error in stringi::stri_detect_regex(text, paste(words, collapse = "|")) : 
# Pattern exceeds limits on size or complexity. (U_REGEX_PATTERN_TOO_BIG)
0
Manuel Bickel