2015-11-22 13 views
6

Ich denke, das ist ein häufiges Problem, und ich fand ziemlich viele Webseiten, darunter einige von SO, aber ich habe nicht verstanden, wie man es implementiert.REGEX in R: Extrahieren von Wörtern aus einer Zeichenfolge

Ich bin neu in REGEX, und ich möchte es in R verwenden, um die ersten paar Wörter aus einem Satz zu extrahieren.

zum Beispiel, wenn mein Satz ist

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

id mag meine Ausgabe haben, als (wenn ich die ersten vier Worte brauchen)

[1] "I love stack overflow" 

oder (wenn ich die letzten vier brauchen Wörter)

[1] "such a cool site" 

natürlich die folgenden Werke

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

, aber ich möchte eine Regex-Lösung für Performance-Probleme versuchen, wie ich mit sehr großen Dateien umgehen müssen (und auch für den Willen es zu wissen)

ich mehrere Links sah, einschließlich Regex to extract first 3 words from a string und http://osherove.com/blog/2005/1/7/using-regex-to-return-the-first-n-words-in-a-string.html

so habe ich versucht, Dinge wie

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

ich andere Sachen versucht, aber es kehrte mich in der Regel entweder die gesamte Zeichenfolge oder die leere Zeichenfolge.

ein weiteres Problem mit substr ist, dass es eine Liste zurückgibt. vielleicht sieht es so aus, als würde der [[]]-Operator die Dinge etwas verlangsamen (??), wenn es um große Dateien geht und Dinge angewendet werden.

sieht es so aus, als ob die in R verwendete Syntax etwas anders ist? danke!

+2

Sie müssen Doppel-Escapes in R Regex verwenden. '\ S' ->' \\ S' –

+0

Sie könnten auch 'stringi :: stri_extract_all_words (z) [[1]] [1: 4]' versuchen, was einfacher zu benutzen ist und keine Regex erfordert. Obwohl Sie die Wörter eine getrennte Werte erhalten werden. –

+0

Könnten Sie nicht einfach die gleiche Idee verwenden, die ich [in Ihrer früheren Frage] geteilt hatte (http://stackoverflow.com/questions/33785594/manipulate-char-vectors-inside-a-data-table-object-in) -r)? Sie müssen nur Ihre Backslashes in R verdoppeln, wie bereits von @stribizhev gezeigt. – A5C1D2H2I1M1N2O1R2T1

Antwort

5

Du hast bereits akzeptiert eine Antwort, aber ich werde dies als ein Mittel, helfen Sie ein wenig über regex in R mehr verstehen teilen, da Sie die Antwort auf immer auf die eigentlich sehr nahe waren besitzen.


Es gibt zwei Probleme mit Ihrem gsub Ansatz:

  1. Sie einzelne Schrägstriche verwendet (\). R verlangt, dass Sie diesen entkommen, da sie Sonderzeichen sind. Sie können sie umgehen, indem Sie einen weiteren umgekehrten Schrägstrich hinzufügen (\\). Wenn Sie nchar("\\") tun, werden Sie sehen, dass es "1" zurückgibt.

  2. Sie haben nicht angegeben, was der Ersatz sein soll. Hier wollen wir nichts ersetzen, aber wir wollen einen bestimmten Teil der Zeichenkette erfassen.Sie erfassen Gruppen in Klammern (...), und Sie können dann auf sie durch die Nummer der Gruppe verweisen. Hier haben wir nur eine Gruppe, daher bezeichnen wir sie als "\\1".

Sie sollten wie etwas versucht haben:

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

Dies resultierte im Wesentlichen sagt:

  • Arbeit von Anfang des Inhalts von "z".
  • Beginn der Erstellung Gruppe 1.
  • finden Nicht-Leerzeichen (wie ein Wort) Leerzeichen gefolgt (\S+\s+) zweimal {2} und dann die nächste Gruppe von Nicht-Whitespaces (\S+). Dies wird uns 3 Wörter bringen, ohne auch den Whitespace nach dem dritten Wort zu erhalten. Wenn Sie also eine andere Anzahl von Wörtern wünschen, ändern Sie den Wert {2} um eins kleiner als die Zahl, nach der Sie tatsächlich suchen.
  • Endgruppe 1 dort.
  • Dann geben Sie einfach den Inhalt der Gruppe 1 (\1) von "z" zurück.

Um die letzten drei Worte zu bekommen, nur die Position der Erfassungsgruppe wechseln und es am Ende des Musters entsprechen setzen.

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

danke. @ Ananda Mahto. Könnten Sie die Regex für die letzten 4 Wörter mit der gleichen Funktion 'sub' geben? –

+1

@FaguiCurtain, ich tauschte einfach die Referenz von fest an den Anfang der Zeile bis zum Ende statt wie: '^. * ((?: \\ S + \\ s +) {2} \\ S +) $'. Ändern Sie "2" zu "3", um 4 statt 3 Wörter zu erhalten. – A5C1D2H2I1M1N2O1R2T1

3

Für die ersten vier Wörter.

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

Für die letzten vier.

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

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

+0

kannst du mir den richtigen Regex mit der Funktion 'sub' geben. Ich habe einen Test an einem 10.000 Sample gemacht und die 'sub' Funktion von Base R ist 30 mal schneller als' str_extract' von 'library (stringr)'. danke –

+0

Ich bin blöd aber weiß nicht, wie man die Funktion zwickt. 'sub (" (?: \\ S + \\ s +) {3} \\ S + (? = \\ s * $) ", ersatz =" ", z, perl = WAHR)' gibt mir zurück '" Ich liebe stack overflow es ist "' was ist alles ABER die letzten 4 Wörter ... –

Verwandte Themen