2015-08-11 11 views
22

Mam to mystring z ogranicznikiem "_". Warunek jest tutaj, jeśli istnieją dwa lub więcej ograniczników, chcę podzielić na drugim ograniczniku i jeśli istnieje tylko jeden separator, chcę podzielić na ".Recal" i uzyskać result, jak pokazano poniżej.Podział ciągu z warunkami w R

mystring<-c("MODY_60.2.ReCal.sort.bam","MODY_116.21_C4U.ReCal.sort.bam","MODY_116.3_C2RX-1-10.ReCal.sort.bam","MODY_116.4.ReCal.sort.bam") 

wynik

"MODY_60.2" "MODY_116.21" "MODY_116.3" "MODY_116.4" 
+4

ciekawe pytanie. Nie wiem, czy istnieje sposób, aby zrobić to za jednym razem. Mogę zhakować to jak 'sub (" (. + _. +) _. + $ "," \\ 1 ", sub (" \\. ReCal. + $ "," ", Mystring))', ale ja "Jestem pewien, że ktoś może to poprawić. – thelatemail

+2

Naśladując logikę w zakresie wyrażeń regularnych, może tak: 'sub (" (? (? =. + _. + _) (. + _. +) _. * | (. +) \\. ReCal. *) "," \\ 1 \\ 2 ", mystring, perl = TRUE)'. – lukeA

+2

Jeśli uda Ci się uzyskać to w jednym regex lub nawet zastosować rozwiązanie @ nongkrong, _please_ przykleja komentarz powyżej kodu, więc twoja przyszła jaźń (lub jakaś osoba, która staje się dozorcą) wie, co próbujesz zrobić. Kilka razy ugryzłem się w siebie, używając "bardzo sprytnego rozwiązania", które moja młodsza jaźń stworzyła, które zajęło całe wieki, aby zapamiętać szczegóły/rozumowanie z tyłu. – hrbrmstr

Odpowiedz

11

Można to zrobić za pomocą gsubfn

library(gsubfn) 
f <- function(x,y,z) if (z=="_") y else strsplit(x, ".ReCal", fixed=T)[[1]][[1]] 
gsubfn("([^_]+_[^_]+)(.).*", f, mystring, backref=2) 
# [1] "MODY_60.2" "MODY_116.21" "MODY_116.3" "MODY_116.4" 

Pozwala to przypadków, gdy masz więcej niż dwa "_" i chcesz podzielić na drugim, na przykład,

mystring<-c("MODY_60.2.ReCal.sort.bam", 
      "MODY_116.21_C4U.ReCal.sort.bam", 
      "MODY_116.3_C2RX-1-10.ReCal.sort.bam", 
      "MODY_116.4.ReCal.sort.bam", 
      "MODY_116.4_asdfsadf_1212_asfsdf", 
      "MODY_116.5.ReCal_asdfsadf_1212_asfsdf", # split by second "_", leaving ".ReCal" 
      "MODY") 

gsubfn("([^_]+_[^_]+)(.).*", f, mystring, backref=2) 
# [1] "MODY_60.2"  "MODY_116.21"  "MODY_116.3"  "MODY_116.4"  
# [5] "MODY_116.4"  "MODY_116.5.ReCal" "MODY"    

W funkcji f, x jest oryginalny ciąg, y i z są następne mecze. Więc jeśli z nie jest "_", to kontynuuje dzielenie przez alternatywny ciąg znaków.

+0

Czy możesz wyjaśnić, co to są te liczby: [[1]] [[1]]; i ta struktura :("([^ _] + _ [^ _] +) (.).* ", f, mystring, backref = 2) – MAPK

+1

@MAPK' [[1]] [[1]] 'indeksuje wynik zwracany przez' strsplit', aby pobrać pierwszą część zwróconego podziału. "[^_] + "regex oznacza" dopasuj wszystko, co nie jest równe "\ _". Tak więc pierwsza część regexu (zawarta w pierwszym zbiorze "()") pasuje do drugiego "\ _", jeśli jest. "(.)" dopasowuje następny znak, aby sprawdzić, czy był drugi "_" (ten odpowiednik odpowiada 'z' w funkcji' f'). – jenesaisquoi

4
gsub('^(.*\\.\\d+).*','\\1',mystring) 
[1] "MODY_60.2" "MODY_116.21" "MODY_116.3" "MODY_116.4" 
+3

To działa, ale nie wykorzystuje pożądanej logiki. Patrzysz na przykładowy ciąg znaków i reinterpretujesz wzorzec, aby go zidentyfikować. Powinieneś przynajmniej podać więcej wyjaśnień, jak to działa. – rbatt

5

Z pakietem stringr:

str_extract(mystring, '.*?_.*?(?=_)|^.*?_.*(?=\\.ReCal)') 
[1] "MODY_60.2" "MODY_116.21" "MODY_116.3" "MODY_116.4" 

Działa również z więcej niż dwoma ogranicznikami.

5

Perl/PCRE ma funkcję resetowania gałęzi , która umożliwia ponowne użycie numeru grupy, gdy przechwytujesz grupy w różnych wersjach i jest traktowana jako jedna grupa przechwytująca.

IMO, ta funkcja jest elegancka, gdy chcesz dostarczyć różne alternatywy.

x <- c('MODY_60.2.ReCal.sort.bam', 'MODY_116.21_C4U.ReCal.sort.bam', 
     'MODY_116.3_C2RX-1-10.ReCal.sort.bam', 'MODY_116.4.ReCal.sort.bam', 
     'MODY_116.4_asdfsadf_1212_asfsdf', 'MODY_116.5.ReCal_asdfsadf_1212_asfsdf', 'MODY') 

sub('^(?|([^_]*_[^_]*)_.*|(.*)\\.ReCal.*)$', '\\1', x, perl=T) 
# [1] "MODY_60.2"  "MODY_116.21"  "MODY_116.3"  "MODY_116.4"  
# [5] "MODY_116.4"  "MODY_116.5.ReCal" "MODY" 
2

Nieco dłużej, ale wymaga mniej regularny wiedzy wyrażenie:

library(stringr) 
indx <- str_locate_all(mystring, "_") 

for (i in seq_along(indx)) { 
    if (nrow(indx[[i]]) == 1) { 
    mystring[i] <- strsplit(mystring[i], ".ReCal")[[1]][1] 
    } else { 
    mystring[i] <- substr(mystring[i], start = 1, stop = indx[[i]][2] - 1) 
    } 
}