J'essaie de déterminer si une chaîne est un sous-ensemble d'une autre chaîne. Par exemple:
chars <- "test"
value <- "es"
Je veux renvoyer VRAI si "valeur" apparaît dans la chaîne "caractères". Dans le scénario suivant, je voudrais renvoyer false:
chars <- "test"
value <- "et"
Utilisez la fonction grepl
grepl(value, chars)
# TRUE
Soupir, il m'a fallu 45 minutes pour trouver la réponse à cette question simple. La réponse est: grepl(needle, haystack, fixed=TRUE)
# Correct
> grepl("1+2", "1+2", fixed=TRUE)
[1] TRUE
> grepl("1+2", "123+456", fixed=TRUE)
[1] FALSE
# Incorrect
> grepl("1+2", "1+2")
[1] FALSE
> grepl("1+2", "123+456")
[1] TRUE
grep
est nommé d'après l'exécutable de Linux, qui est lui-même un acronyme de "G lobal R egulaire E xpression P rint ", il lirait les lignes d’entrée puis les imprimerait si elles correspondaient aux arguments que vous avez donnés. "Global" signifiait que la correspondance pouvait avoir lieu n'importe où sur la ligne d'entrée. Je vais expliquer "Expression régulière" ci-dessous, mais l'idée est que c'est un moyen plus intelligent de faire correspondre la chaîne (R appelle ce "caractère", par exemple, class("abc")
), et "Print" parce qu’il s’agit d’un programme en ligne de commande, émettre une sortie signifie qu’il s’imprime dans sa chaîne de sortie.
Maintenant, le programme grep
est essentiellement un filtre, des lignes d’entrée aux lignes de sortie. Et il semble que la fonction grep
de R nécessitera un tableau d'entrées. Pour des raisons qui me sont totalement inconnues (j'ai commencé à jouer avec R il y a à peu près une heure), il renvoie un vecteur des index correspondants, plutôt qu'une liste de correspondances.
Mais revenons à votre question initiale. Ce que nous voulons vraiment, c’est de savoir si nous avons trouvé l’aiguille dans la botte de foin, une valeur vrai/faux. Ils ont apparemment décidé de nommer cette fonction grepl
, comme dans "grep" mais avec une valeur de retour "L ogical" (ils appellent valeurs logiques vraies et fausses, par exemple class(TRUE)
).
Nous savons donc maintenant d'où vient le nom et ce qu'il est censé faire. Permet de revenir aux expressions régulières. Les arguments, même s’il s’agit de chaînes, sont utilisés pour construire des expressions régulières (dorénavant: regex). Une expression rationnelle est un moyen de faire correspondre une chaîne (si cette définition vous irrite, laissez-la aller). Par exemple, la regex a
correspond au caractère "a"
, la regex a*
correspond au caractère "a"
0 fois ou plus, et la regex a+
correspond au caractère "a"
1 fois ou plus. Par conséquent, dans l'exemple ci-dessus, l'aiguille que nous recherchons 1+2
, lorsqu'elle est traitée comme une regex, signifie "un ou plusieurs 1 suivis d'un 2" ... mais la nôtre est suivie d'un plus!
Donc, si vous utilisiez la grepl
sans régler fixed
, vos aiguilles seraient accidentellement des meules de foin, et cela fonctionnerait accidentellement assez souvent, nous pouvons même constater que cela fonctionne également à l'exemple du PO. Mais c'est un bug latent! Nous devons lui dire que l’entrée est une chaîne, pas une regex, ce qui est apparemment ce à quoi sert fixed
. Pourquoi fixe? Pas la moindre idée, marquez cette réponse b/c, vous allez probablement devoir la regarder 5 fois de plus avant de la mémoriser.
Plus votre code est bon, moins vous devez connaître l’histoire pour en comprendre le sens. Chaque argument peut avoir au moins deux valeurs intéressantes (sinon, ce ne serait pas nécessairement un argument), la documentation répertorie 9 arguments ici, ce qui signifie qu'il y a au moins 2 ^ 9 = 512 façons de l'invoquer, ce qui représente beaucoup de travail pour écrivez, testez et souvenez-vous ... dissociez ces fonctions (séparez-les, supprimez les dépendances les unes par rapport aux autres, les chaînes de caractères sont différentes des choses regex, elles sont différentes de celles des vecteurs). Certaines options s’excluent également mutuellement. Ne donnez pas aux utilisateurs des moyens incorrects d’utiliser le code, c’est-à-dire que l’appel problématique doit être structurellement dépourvu de sens (par exemple, passer une option qui n’existe pas), pas logiquement dénué de sens (vous devez émettre un avertissement pour l'expliquer). Métaphoriquement: remplacer la porte d'entrée située sur le côté du 10ème étage par un mur est mieux que de suspendre un panneau qui met en garde contre son utilisation, mais que cela vaut mieux que ni l'un ni l'autre. Dans une interface, la fonction définit l'apparence des arguments, et non l'appelant (l'appelant dépend de la fonction, en déduisant tout ce que tout le monde peut appeler, la fonction dépend également des appelants, et ce type de dépendance cyclique va rapidement encombrer un système et ne jamais fournir les avantages escomptés). Méfiez-vous des types équivoques, c’est un défaut de conception que des éléments comme TRUE
et 0
et "abc"
soient tous des vecteurs.
Vous voulez grepl
:
> chars <- "test"
> value <- "es"
> grepl(value, chars)
[1] TRUE
> chars <- "test"
> value <- "et"
> grepl(value, chars)
[1] FALSE
Utilisez cette fonction du package stringi
:
> stri_detect_fixed("test",c("et","es"))
[1] FALSE TRUE
Quelques repères:
library(stringi)
set.seed(123L)
value <- stri_Rand_strings(10000, ceiling(runif(10000, 1, 100))) # 10000 random ASCII strings
head(value)
chars <- "es"
library(microbenchmark)
microbenchmark(
grepl(chars, value),
grepl(chars, value, fixed=TRUE),
grepl(chars, value, Perl=TRUE),
stri_detect_fixed(value, chars),
stri_detect_regex(value, chars)
)
## Unit: milliseconds
## expr min lq median uq max neval
## grepl(chars, value) 13.682876 13.943184 14.057991 14.295423 15.443530 100
## grepl(chars, value, fixed = TRUE) 5.071617 5.110779 5.281498 5.523421 45.243791 100
## grepl(chars, value, Perl = TRUE) 1.835558 1.873280 1.956974 2.259203 3.506741 100
## stri_detect_fixed(value, chars) 1.191403 1.233287 1.309720 1.510677 2.821284 100
## stri_detect_regex(value, chars) 6.043537 6.154198 6.273506 6.447714 7.884380 100
Aussi, peut être fait en utilisant la bibliothèque "stringr":
> library(stringr)
> chars <- "test"
> value <- "es"
> str_detect(chars, value)
[1] TRUE
### For multiple value case:
> value <- c("es", "l", "est", "a", "test")
> str_detect(chars, value)
[1] TRUE FALSE TRUE FALSE TRUE
Juste au cas où vous voudriez aussi vérifier si une chaîne (ou un ensemble de chaînes) contient plusieurs sous-chaînes, vous pouvez également utiliser le caractère '|' entre deux sous-chaînes.
>substring="as|at"
>string_vector=c("ass","ear","eye","heat")
>grepl(substring,string_vector)
Tu auras
[1] TRUE FALSE FALSE TRUE
puisque le premier mot a une sous-chaîne "en", et le dernier mot contient une sous-chaîne "à"
Utilisez grep
ou grepl
mais sachez si vous voulez ou non utiliser des expressions régulières.
Par défaut, grep
et les entités associées utilisent une expression régulière , et non une sous-chaîne littérale. Si vous ne vous attendez pas à cela et que vous essayez de faire correspondre une expression rationnelle invalide, cela ne fonctionne pas:
> grep("[", "abc[")
Error in grep("[", "abc[") :
invalid regular expression '[', reason 'Missing ']''
Pour faire un vrai test de sous-chaîne, utilisez fixed = TRUE
.
> grep("[", "abc[", fixed = TRUE)
[1] 1
Si vous voulez regex, c'est bien, mais ce n'est pas ce que le PO semble demander.
Vous pouvez utiliser grep
grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)