it-swarm.com.de

Testen Sie, ob Zeichen in einer Zeichenfolge enthalten sind

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"
235
mike

Verwenden Sie die Funktion grepl

grepl(value, chars)
# TRUE
332
smu

Antworten

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

Interpretation

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!

1+2 as a regex

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.

Ein paar abschließende Gedanken

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.

132
Joshua Cheek

Sie möchten grepl:

> chars <- "test"
> value <- "es"
> grepl(value, chars)
[1] TRUE
> chars <- "test"
> value <- "et"
> grepl(value, chars)
[1] FALSE
31
Justin

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
22
bartektartanus

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
16
Surya

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

15
C. Zeng

Verwenden Sie grep oder greplachten 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.

9
Chris

Sie können grep verwenden.

grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)
7
nico