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"
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.
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ń.
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!
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.
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
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
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
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 "
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.
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)
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.
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