Ich versuche festzustellen, ob eine Zeichenfolge eine Teilmenge einer anderen Zeichenfolge ist. Zum Beispiel:
chars <- "test"
value <- "es"
Ich möchte TRUE zurückgeben, wenn "value" als Teil der Zeichenfolge "chars" angezeigt wird. Im folgenden Szenario möchte ich false zurückgeben:
chars <- "test"
value <- "et"
Verwenden Sie die Funktion grepl
grepl(value, chars)
# TRUE
Seufz, ich habe 45 Minuten gebraucht, um die Antwort auf diese einfache Frage zu finden. Die Antwort lautet: 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
ist nach der ausführbaren Linux-Datei benannt, die selbst ein Akronym für "G lobal R egular E xpression P rint ", liest Eingabezeilen und druckt sie dann aus, wenn sie mit den von Ihnen angegebenen Argumenten übereinstimmen. "Global" bedeutete, dass die Übereinstimmung an einer beliebigen Stelle in der Eingabezeile auftreten konnte. Im Folgenden wird "Regulärer Ausdruck" erläutert. Die Idee ist jedoch, dass die Übereinstimmung mit der Zeichenfolge intelligenter ist (R nennt dieses "Zeichen", z. B. class("abc")
. ) und "Print", da es sich um ein Kommandozeilenprogramm handelt.
Das Programm grep
ist im Grunde genommen ein Filter von Eingabezeilen zu Ausgabezeilen. Und es scheint, dass die grep
-Funktion von R in ähnlicher Weise eine Reihe von Eingaben akzeptiert. Aus Gründen, die mir völlig unbekannt sind (ich habe erst vor ungefähr einer Stunde angefangen, mit R zu spielen), wird ein Vektor der übereinstimmenden Indizes und keine Liste der Übereinstimmungen zurückgegeben.
Aber zurück zu Ihrer ursprünglichen Frage: Wir möchten wirklich wissen, ob wir die Nadel im Heuhaufen gefunden haben, ein wahrer/falscher Wert. Sie haben anscheinend beschlossen, diese Funktion grepl
zu nennen, wie in "grep", aber mit einem "L ogischen" Rückgabewert (sie rufen auf) wahre und falsche logische Werte, zB class(TRUE)
).
Jetzt wissen wir also, woher der Name kommt und was er tun soll. Kommen wir zurück zu regulären Ausdrücken. Obwohl die Argumente Zeichenfolgen sind, werden sie zum Erstellen regulärer Ausdrücke verwendet (fortan: regulärer Ausdruck). Ein regulärer Ausdruck ist eine Möglichkeit, eine Zeichenfolge abzugleichen (wenn Sie diese Definition irritiert, lassen Sie es los). Beispielsweise stimmt der reguläre Ausdruck a
mit dem Zeichen "a"
überein, der reguläre Ausdruck a*
stimmt mit dem Zeichen "a"
0 oder mehrmals überein, und der reguläre Ausdruck a+
würde mit dem übereinstimmen Zeichen "a"
1 oder mehrmals. Daher bedeutet im obigen Beispiel die Nadel, nach der wir suchen 1+2
, wenn sie als Regex behandelt wird, "eine oder mehrere 1 gefolgt von einer 2" ... aber auf unsere folgt ein Plus!
Wenn Sie also grepl
verwenden, ohne fixed
einzustellen, wären Ihre Nadeln versehentlich Heuhaufen, und das würde versehentlich ziemlich oft funktionieren. Wir können sehen, dass es sogar für das Beispiel des OP funktioniert. Aber das ist ein latenter Bug! Wir müssen sagen, dass es sich bei der Eingabe um eine Zeichenfolge handelt, nicht um eine Regex, wofür fixed
anscheinend gedacht ist. Warum behoben? Keine Ahnung, setzen Sie ein Lesezeichen für diese Antwort, da Sie sie wahrscheinlich noch fünf Mal nachschlagen müssen, bevor Sie sie auswendig lernen können.
Je besser Ihr Code ist, desto weniger Geschichte müssen Sie wissen, um einen Sinn daraus zu ziehen. Jedes Argument kann mindestens zwei interessante Werte haben (andernfalls müsste es kein Argument sein). Die Dokumentation listet hier 9 Argumente auf, was bedeutet, dass es mindestens 2 ^ 9 = 512 Möglichkeiten gibt, es aufzurufen. Das ist eine Menge Arbeit schreibe, teste und erinnere dich ... entkopple solche Funktionen (teile sie auf, entferne Abhängigkeiten voneinander, String-Dinge sind anders als Regex-Dinge sind anders als Vektorsachen). Einige der Optionen schließen sich auch gegenseitig aus. Geben Sie den Benutzern keine falschen Möglichkeiten, den Code zu verwenden. Das heißt, der problematische Aufruf sollte strukturell unsinnig sein (z. B. Übergeben einer nicht vorhandenen Option), nicht logisch unsinnig (sofern erforderlich) eine Warnung aus, um es zu erklären). Bildlich ausgedrückt: Das Ersetzen der Vordertür an der Seite des 10. Stocks durch eine Wand ist besser als das Aufhängen eines Zeichens, das vor seiner Verwendung warnt, aber eines ist besser als keines. In einer Schnittstelle definiert die Funktion, wie die Argumente aussehen sollen, nicht der Aufrufer (da der Aufrufer von der Funktion abhängt und alles ableitet, womit jeder ihn jemals aufrufen möchte, hängt die Funktion auch vom Aufrufer und diesem Typ ab zyklischer Abhängigkeit wird ein System schnell verstopfen und niemals den erwarteten Nutzen bringen). Seien Sie sehr vorsichtig bei nicht eindeutigen Typen, es ist ein Konstruktionsfehler, dass Dinge wie TRUE
und 0
und "abc"
alle Vektoren sind.
Sie möchten grepl
:
> chars <- "test"
> value <- "es"
> grepl(value, chars)
[1] TRUE
> chars <- "test"
> value <- "et"
> grepl(value, chars)
[1] FALSE
Verwenden Sie diese Funktion aus dem Paket stringi
:
> stri_detect_fixed("test",c("et","es"))
[1] FALSE TRUE
Einige Benchmarks:
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
Kann auch gemacht werden mit "stringr" library:
> 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
Nur für den Fall, dass Sie auch prüfen möchten, ob eine Zeichenfolge (oder eine Reihe von Zeichenfolgen) mehrere Unterzeichenfolgen enthält, können Sie auch das '|' zwischen zwei Teilzeichenfolgen.
>substring="as|at"
>string_vector=c("ass","ear","eye","heat")
>grepl(substring,string_vector)
Sie erhalten
[1] TRUE FALSE FALSE TRUE
da das 1. Wort den Teilstring "as" hat und das letzte Wort den Teilstring "at" enthält
Verwenden Sie grep
oder grepl
achten Sie jedoch darauf, ob Sie reguläre Ausdrücke verwenden möchten.
Standardmäßig verwenden grep
und related einen regulären Ausdruck , um eine Übereinstimmung zu erzielen, und keinen wörtlichen Teilstring. Wenn Sie dies nicht erwarten und versuchen, eine Übereinstimmung mit einem ungültigen regulären Ausdruck zu erzielen, funktioniert dies nicht:
> grep("[", "abc[")
Error in grep("[", "abc[") :
invalid regular expression '[', reason 'Missing ']''
Verwenden Sie fixed = TRUE
, um einen True-Substring-Test durchzuführen.
> grep("[", "abc[", fixed = TRUE)
[1] 1
Wenn Sie Regex wollen, großartig, aber das scheint das OP nicht zu fragen.
Sie können grep
verwenden.
grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)