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.
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 = "|")
Voici une solution utilisant le paquet stringr
require(stringr)
mylist = c("1100", "0010", "1001", "1111")
str_locate(mylist, "000|001|100")
Utilisez l'argument -e pour ajouter des motifs supplémentaires:
echo '1100' | grep -e '001' -e '110' -e '101'
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
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
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)