Sprawdź, czy znaki są w łańcuchu

Próbuję ustalić, czy łańcuch jest podzbiorem innego łańcucha. Na przykład:

chars <- "test"
value <- "es"

Chcę zwrócić TRUE, Jeśli jako część łańcucha znaków pojawia się "value". W poniższym scenariuszu chciałbym zwrócić false:

chars <- "test"
value <- "et"
Author: Jaap, 2012-04-12

9 answers

Użyj funkcji grepl

grepl( needle, haystack, fixed = TRUE)

Like so:

grepl(value, chars, fixed = TRUE)
# TRUE

Użyj ?grepl, aby dowiedzieć się więcej.

 430
Author: smu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-21 06:44:50

Odpowiedź

Szukanie odpowiedzi na to proste pytanie Zajęło mi 45 minut. Odpowiedź brzmi: 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

Interpretacja

grep nazwa pochodzi od pliku wykonywalnego Linuksa, który sam w sobie jest akronimem" Global Regular Expression print", czyta linie danych wejściowych i wypisuje je, jeśli pasują do podanych przez Ciebie argumentów. "Global" oznaczało, że mecz może nastąpić w dowolnym miejscu na linii wejściowej, wyjaśnię Poniżej "Wyrażenie regularne", ale chodzi o to, że jest to mądrzejszy sposób dopasowania ciągu znaków (r nazywa ten "znak", np class("abc")), i "Drukuj", ponieważ jest to program wiersza poleceń, emitting output oznacza, że drukuje na swoim łańcuchu wyjściowym.

Program grep jest w zasadzie filtrem, od linii wejścia do linii wyjścia. I wygląda na to, że funkcja R grep podobnie przyjmie szereg wejść. Z zupełnie nieznanych mi powodów (zacząłem grać z R dopiero godzinę temu), to zwraca wektor indeksów, które pasują, a nie listę dopasowań.

Ale wracając do twojego pierwotnego pytania, tak naprawdę chcemy wiedzieć, czy znaleźliśmy igłę w stogu siana, wartość PRAWDA/FAŁSZ. Najwyraźniej zdecydowali się nazwać tę funkcję grepl, jak w" grep", ale z wartością zwracaną " L ogical " (nazywają wartości logiczne true I false, np class(TRUE)).

Więc teraz wiemy, skąd wzięła się nazwa i co ma zrobić. Lets get back to Regular Wyrażenia. Argumenty, mimo że są ciągami, są używane do budowania wyrażeń regularnych (odtąd: regex). Regex jest sposobem dopasowania ciągu znaków (jeśli ta definicja cię irytuje, odpuść). Na przykład regex a pasuje do znaku "a", regex a* pasuje do znaku "a" 0 lub więcej razy, a regex a+ pasuje do znaku "a" 1 lub więcej razy. Stąd w powyższym przykładzie igła, której szukamy 1+2, traktowana jako regex, oznacza " jedną lub więcej 1, a następnie 2"... ale za naszym idzie plus!

1 + 2 jako regex

Więc, jeśli użyłbyś grepl bez ustawiania fixed, twoje igły przypadkowo byłyby stogami siana, a to przypadkowo działałoby dość często, widzimy, że działa nawet na przykładzie OP. Ale to ukryty błąd! Musimy powiedzieć, że wejście jest ciągiem znaków, a nie regex, który najwyraźniej jest tym, do czego służy fixed. Dlaczego Naprawiono? Nie mam pojęcia, zakładka ta odpowiedź b / c prawdopodobnie będziesz musiał szukać to się 5 razy więcej, zanim się go zapamiętać.

Kilka ostatnich myśli

Im lepszy jest Twój kod, tym mniej historii musisz znać, aby nadać mu sens. Każdy argument może mieć co najmniej dwie interesujące wartości( w przeciwnym razie nie musiałby być argumentem), docs wymienia tutaj 9 argumentów, co oznacza, że jest co najmniej 2^9=512 sposobów na wywołanie go, to dużo pracy do napisania, przetestowania i zapamiętania... oddzielić takie funkcje (podzielić je, usunąć zależności od siebie, rzeczy string są inne niż regex rzeczy są inne niż rzeczy wektorowe). Niektóre opcje również wzajemnie się wykluczają, nie podawaj użytkownikom niewłaściwych sposobów użycia kodu, tzn. problematyczne wywołanie powinno być strukturalnie nonsensowne( np. podanie opcji, która nie istnieje), a nie logicznie nonsensowne (gdzie musisz emitować ostrzeżenie, aby to wyjaśnić). Mówiąc metaforycznie: wymiana drzwi wejściowych od strony 10. piętra na ścianę jest lepsza niż powieszenie znaku ostrzegającego przeciwko jego użyciu, ale albo jest lepszy niż żaden. W interfejsie funkcja określa, jak powinny wyglądać argumenty, a nie wywołujący (ponieważ wywołujący zależy od funkcji, wnioskując wszystko, co każdy może kiedykolwiek chcieć wywołać, sprawia, że funkcja zależy również od wywołujących, a tego typu cykliczne zależności szybko zatkają system i nigdy nie zapewnią oczekiwanych korzyści). Należy bardzo uważać na równorzędne typy, to wada konstrukcyjna, że rzeczy takie jak TRUE i 0 i {[20] } są wektorami.

 182
Author: Joshua Cheek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-15 17:48:53

Chcesz grepl:

> chars <- "test"
> value <- "es"
> grepl(value, chars)
[1] TRUE
> chars <- "test"
> value <- "et"
> grepl(value, chars)
[1] FALSE
 32
Author: Justin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-12 17:28:40

Użyj tej funkcji z stringi pakietu:

> stri_detect_fixed("test",c("et","es"))
[1] FALSE  TRUE

Niektóre benchmarki:

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
 29
Author: bartektartanus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-14 16:45:38

Można również wykonać używając biblioteki "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
 26
Author: Surya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-14 02:38:39

W przypadku, gdy chcesz sprawdzić, czy łańcuch znaków (lub zestaw łańcuchów) zawiera wiele podciągów, możesz również użyć znaku ' / ' pomiędzy dwoma podciągami.

>substring="as|at"
>string_vector=c("ass","ear","eye","heat") 
>grepl(substring,string_vector)

Dostaniesz

[1]  TRUE FALSE FALSE  TRUE

Ponieważ pierwsze słowo ma podłańcuch "as", a ostatnie słowo zawiera podłańcuch " at "

 21
Author: C. Zeng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-25 09:04:18

Użyj grep lub grepl pamiętaj jednak, czy chcesz używać wyrażeń regularnych .

Domyślnie grep i powiązane przyjmują Wyrażenie regularne do dopasowania, a nie dosłowny podłańcuch. Jeśli nie spodziewasz się tego i próbujesz dopasować niepoprawne Wyrażenie regularne, to nie działa:

> grep("[", "abc[")
Error in grep("[", "abc[") : 
  invalid regular expression '[', reason 'Missing ']''

Aby wykonać prawdziwy test podcięcia, użyj fixed = TRUE.

> grep("[", "abc[", fixed = TRUE)
[1] 1

Jeśli chcesz regex, świetnie, ale nie o to prosi OP.

 10
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-13 21:59:25

Możesz użyć grep

grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)
 7
Author: nico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-12 17:29:03

Podobny problem tutaj: biorąc pod uwagę łańcuch i listę słów kluczowych, Wykryj, które, jeśli w ogóle, słowa kluczowe są zawarte w łańcuchu.

Zalecenia z tego wątku sugerują stringr ' S str_detect i grepl. Oto benchmarki z pakietu microbenchmark:

Za pomocą

map_keywords = c("once", "twice", "few")
t = "yes but only a few times"

mapper1 <- function (x) {
  r = str_detect(x, map_keywords)
}

mapper2 <- function (x) {
  r = sapply(map_keywords, function (k) grepl(k, x, fixed = T))
}

A potem

microbenchmark(mapper1(t), mapper2(t), times = 5000)

Znajdujemy

Unit: microseconds
       expr    min     lq     mean  median      uq      max neval
 mapper1(t) 26.401 27.988 31.32951 28.8430 29.5225 2091.476  5000
 mapper2(t) 19.289 20.767 24.94484 23.7725 24.6220 1011.837  5000

Jak widać, ponad 5000 iteracji wyszukiwania słów kluczowych za pomocą str_detect i grepl nad praktycznym ciągiem i wektorem słów kluczowych, grepl działa nieco lepiej niż str_detect.

Wynikiem jest wektor logiczny r, który określa, które, jeśli w ogóle, słowa kluczowe są zawarte w łańcuchu.

Dlatego zalecam użycie grepl do określenia, czy jakiekolwiek słowa kluczowe są w łańcuchu.

 0
Author: Alex L,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-07 16:34:43