2011-08-04 16 views
17

chcę zobaczyć, czy "001" lub "100" lub "000" występuje ciąg 4 znaków 0 i 1. Na przykład ciąg 4 znaków może być podobny do "1100" lub "0010" lub "1001" lub "1111". Jak dopasować wiele ciągów w ciągu za pomocą pojedynczego polecenia?Dopasowane ciąg z wykorzystaniem różnych możliwości grep

Wiem, że grep może być użyty do dopasowywania wzorca, ale używając polecenia grep, mogę sprawdzić tylko jeden ciąg na raz. Chcę wiedzieć, czy wiele ciągów może być używanych z innym poleceniem lub z samym grep.

Odpowiedz

37

Tak, można. Wzorzec | w kodzie grep ma to samo znaczenie co or. Aby przetestować swój wzorzec, użyj wzoru "001|100|000". Jednocześnie, grep jest wektoryzowane, więc to wszystko może być wykonane w jednym kroku (. W tym przypadku pierwsze trzy)

x <- c("1100", "0010", "1001", "1111") 
pattern <- "001|100|000" 

grep(pattern, x) 
[1] 1 2 3 

ta zwraca indeks które z wektorów zawartych wzór pasujący

Czasami wygodniej jest mieć wektor logiczny, który mówi, który z elementów w twoim wektorze został dopasowany. Następnie można użyć grepl:

grepl(pattern, x) 
[1] TRUE TRUE TRUE FALSE 

Zobacz ?regex o pomoc na temat wyrażeń regularnych w R.


Edit: Aby uniknąć tworzenia wzorzec ręcznie możemy użyć paste:

myValues <- c("001", "100", "000") 
pattern <- paste(myValues, collapse = "|") 
+0

@ andrie, to absolutnie genialne, zakładało, że jest to niemożliwe od lat, a to po prostu proste wyrażenie,

+4

@ Davavaraburg :-) Nauczyłem się z gorzkiego doświadczenia, że ​​nic nie jest niemożliwe w R. To zawsze jest tylko kwestia w jaki sposób! – Andrie

2

Użyj -e argumentu, aby dodać dodatkowe wzory:

echo '1100' | grep -e '001' -e '110' -e '101' 
+2

Przykro mi, ale zapomniałem wspomnieć, że chcę to zrobić w R. – Narayani

+0

jest to przydatne w każdym razie. – marbel

6

Oto jedno rozwiązanie z wykorzystaniem stringr pakiet

require(stringr) 
mylist = c("1100", "0010", "1001", "1111") 
str_locate(mylist, "000|001|100") 
1

Można również użyć operatora %like% z data.table bibliotece.

library(data.table) 

# input 
    x <- c("1100", "0010", "1001", "1111") 
    pattern <- "001|100|000" 

# check for pattern 
    x %like% pattern 

> [1] TRUE TRUE TRUE FALSE 
+0

Zauważ, że '% like%' jest po prostu opakowaniem dla 'grepl', sprawdź'?% Jak% '" Argumenty: ... \t wzorzec \t Przekazywany do grepl. ". Przynajmniej do 'data.table' wersji 1.10.4-2. –

1

Jeśli chcesz logiczną wektor następnie należy sprawdzić stri_detect funkcji z stringi opakowaniu. W twoim przypadku wzór jest regex, więc korzystać z tego jeden:

stri_detect_regex(x, pattern) 
## [1] TRUE TRUE TRUE FALSE 

a niektóre odniesienia:

require(microbenchmark) 
test <- stri_paste(stri_rand_strings(100000, 4, "[0-1]")) 
head(test) 
## [1] "0001" "1111" "1101" "1101" "1110" "0110" 
microbenchmark(stri_detect_regex(test, pattern), grepl(pattern, test)) 
Unit: milliseconds 
          expr  min  lq  mean median  uq  max neval 
stri_detect_regex(test, pattern) 29.67405 30.30656 31.61175 30.93748 33.14948 35.90658 100 
      grepl(pattern, test) 36.72723 37.71329 40.08595 40.01104 41.57586 48.63421 100 
0

przepraszam za tę dodatkową odpowiedź, ale jest zbyt wiele linii w komentarzu.

Chciałem tylko przypomnieć, że liczba elementów, które można wkleić razem za pomocą paste(..., collapse = "|"), aby można je było wykorzystać jako pojedynczy pasujący wzór, jest ograniczona - patrz poniżej. Może ktoś może powiedzieć, gdzie dokładnie jest limit? Wprawdzie liczba ta może nie być realistyczna, ale w zależności od zadania, które należy wykonać, nie należy jej całkowicie wykluczać z naszych rozważań.

Dla naprawdę dużej liczby elementów potrzebna jest pętla do sprawdzenia każdego elementu wzoru.

set.seed(0) 
samplefun <- function(n, x, collapse){ 
    paste(sample(x, n, replace=TRUE), collapse=collapse) 
} 

words <- sapply(rpois(10000000, 8) + 1, samplefun, letters, '') 
text <- sapply(rpois(1000, 5) + 1, samplefun, words, ' ') 

#since execution takes a while, I have commented out the following lines 

#result <- grepl(paste(words, collapse = "|"), text) 

# Error in grepl(pattern, text) : 
# invalid regular expression 
# 'wljtpgjqtnw|twiv|jphmer|mcemahvlsjxr|grehqfgldkgfu| 
# ... 

#result <- stringi::stri_detect_regex(text, paste(words, collapse = "|")) 

# Error in stringi::stri_detect_regex(text, paste(words, collapse = "|")) : 
# Pattern exceeds limits on size or complexity. (U_REGEX_PATTERN_TOO_BIG)