2015-11-22 21 views
6

Domyślam się, że jest to powszechny problem i znalazłem sporo stron internetowych, w tym niektóre z SO, ale nie udało mi się zrozumieć, jak je wdrożyć.REGEX w R: wyodrębnianie słów z łańcucha

Jestem nowy dla REGEX i chciałbym użyć go w R, aby wyodrębnić kilka pierwszych słów ze zdania.

na przykład, jeśli moje zdanie jest

z = "I love stack overflow it is such a cool site" 

id lubią mieć moje wyjście jako (jeśli muszę pierwszych czterech słów)

[1] "I love stack overflow" 

lub (jeśli muszę ostatnie cztery słów)

[1] "such a cool site" 

oczywiście, następujące prace

paste(strsplit(z," ")[[1]][1:4],collapse=" ") 
paste(strsplit(z," ")[[1]][7:10],collapse=" ") 

ale chciałbym spróbować regex rozwiązanie problemów z wydajnością, jak trzeba do czynienia z bardzo dużych plików (a także przez wzgląd na wiedząc o tym)

Spojrzałem na kilka linków, w tym Regex to extract first 3 words from a string i http://osherove.com/blog/2005/1/7/using-regex-to-return-the-first-n-words-in-a-string.html

więc spróbowałem rzeczy jak

gsub("^((?:\S+\s+){2}\S+).*",z,perl=TRUE) 
Error: '\S' is an unrecognized escape in character string starting ""^((?:\S" 

próbowałem innych rzeczy, ale to zwykle zwrócone mnie też cały ciąg lub pusty łańcuch.

Kolejnym problemem z substr jest to, że zwraca listę. może wygląda na to, że operator [[]] spowalnia nieco działanie (??), kiedy ma do czynienia z dużymi plikami i robi rzeczy.

Wygląda na to, że składnia używana w R jest nieco inna? dzięki!

+2

Musisz użyć podwójnych ucieczek w R regex. '\ S' ->' \\ S' –

+0

Można również wypróbować 'stringi :: stri_extract_all_words (z) [[1]] [1: 4]' które jest łatwiejsze w użyciu i nie wymaga znajomości regex. Chociaż otrzymasz słowa oddzielne wartości. –

+0

Nie możesz po prostu użyć tej samej idei, którą udostępniłem [we wcześniejszym pytaniu] (http://stackoverflow.com/questions/33785594/manipulate-char-vectors-inside-a-data-table-object-in -r)? Musisz tylko podwoić swoje ukośniki w R, jak już zauważyła @stribizhev. – A5C1D2H2I1M1N2O1R2T1

Odpowiedz

5

zostały już zaakceptowane odpowiedź, ale mam zamiar podzielić się tym jako sposób pomaga zrozumieć trochę więcej o regex w badania, ponieważ były rzeczywiście bardzo blisko do uzyskania odpowiedzi na swoje posiadać.


Istnieją dwa problemy z podejściem gsub:

  1. Użyłeś pojedyncze backslashy (\). R wymaga od nich ucieczki, ponieważ są one znakami specjalnymi. Uciekniesz od nich, dodając kolejny ukośnik odwrotny (\\). Jeśli wykonasz nchar("\\"), zobaczysz, że zwraca "1".

  2. Nie określono, co należy zastąpić. Tutaj nie chcemy niczego zastępować, ale chcemy uchwycić określoną część ciągu.Przechwytujesz grupy w nawiasach: (...), a następnie możesz odwoływać się do nich według numeru grupy. Tutaj mamy tylko jedną grupę, więc nazywamy ją "\\1".

Należy próbowali coś takiego:

sub("^((?:\\S+\\s+){2}\\S+).*", "\\1", z, perl = TRUE) 
# [1] "I love stack" 

ta jest zasadniczo mówiąc:

  • Pracy od początku treścią "z".
  • rozpocząć tworzenie grupy 1.
  • Znajdź non-spacji (jak w słowie), a następnie spacji (\S+\s+) dwa razy {2} a następnego zestawu nie-białych znaków (\S+). W ten sposób otrzymamy 3 słowa, a także nie otrzymamy białych znaków za trzecim słowem. Tak więc, jeśli chcesz inną liczbę słów, zmień {2} tak, aby była o jeden mniejsza od liczby, której faktycznie szukasz.
  • Zakończ grupę pierwszą.
  • Następnie, po prostu zwróć zawartość grupy 1 (\1) z "z".

Aby uzyskać trzy ostatnie słowa, wystarczy przełączyć pozycję grupy przechwytywania i umieścić go na końcu wzorca aby dopasować.

sub("^.*\\s+((?:\\S+\\s+){2}\\S+)$", "\\1", z, perl = TRUE) 
# [1] "a cool site" 
+0

dzięki. @Ananda Mahto. czy możesz podać wyrażenie regularne dla ostatnich 4 słów używając tej samej funkcji 'sub'? –

+1

@FaguiCurtain, właśnie zamieniłem odniesienie z ustalonego na początek linii na koniec, zamiast: '^. * ((?: \\ S + \\ s +) {2} \\ S +) $'. Zmień "2" na "3", aby uzyskać 4 słowa zamiast 3. – A5C1D2H2I1M1N2O1R2T1

3

Za uzyskanie pierwszych czterech słów.

library(stringr) 
str_extract(x, "^\\s*(?:\\S+\\s+){3}\\S+") 

Za zdobycie ostatnich czterech.

str_extract(x, "(?:\\S+\\s+){3}\\S+(?=\\s*$)") 
+0

lub 'sub ("^\\ s * ((?? \ \ S + \\ s +) {3} \\ S +) . * "," \\ 1 ", x)' –

+0

czy możesz podać poprawne wyrażenie za pomocą funkcji 'sub'. Zrobiłem test na próbce 10 000, a funkcja 'sub' z bazy R jest 30 razy szybsza niż' str_extract' z 'library (stringr)'. dzięki –

+0

Jestem głupi, ale nie wiem jak poprawić funkcję. 'sub (" (?: \\ S + \\ s +) {3} \\ S + (? = \\ s * $) ", zamiennik =" ", z, perl = PRAWDA)' zwraca mnie '" Uwielbiam przepełnienie stosu to "', które jest wszystkim, ale ostatnie 4 słowa ... –