Regex-Gruppenerfassung in R mit mehreren Erfassungsgruppen


94

Ist es in R möglich, die Gruppenerfassung aus einer Übereinstimmung mit regulären Ausdrücken zu extrahieren? Soweit ich sagen kann, nichts von grep, grepl, regexpr, gregexpr, sub, oder gsubdie Gruppe Captures zurück.

Ich muss Schlüssel-Wert-Paare aus Zeichenfolgen extrahieren, die folgendermaßen codiert sind:

\((.*?) :: (0\.[0-9]+)\)

Ich kann immer nur mehrere Greps mit vollständiger Übereinstimmung oder eine externe (Nicht-R-) Verarbeitung durchführen, aber ich hatte gehofft, dass ich alles innerhalb von R ausführen kann. Gibt es eine Funktion oder ein Paket, das eine solche Funktion bietet, um dies zu tun?

Antworten:


118

str_match(), aus dem stringrPaket, wird dies tun. Es wird eine Zeichenmatrix mit einer Spalte für jede Gruppe in der Übereinstimmung (und einer für die gesamte Übereinstimmung) zurückgegeben:

> s = c("(sometext :: 0.1231313213)", "(moretext :: 0.111222)")
> str_match(s, "\\((.*?) :: (0\\.[0-9]+)\\)")
     [,1]                         [,2]       [,3]          
[1,] "(sometext :: 0.1231313213)" "sometext" "0.1231313213"
[2,] "(moretext :: 0.111222)"     "moretext" "0.111222"    

1
und str_match_all()alle Gruppen in einem
regulären Ausdruck zu finden

Wie kann ich nur die erfassten Gruppen für [, 1] drucken?
nenur

Nicht sicher, wonach Sie suchen. Die erfassten Gruppen sind die Spalten 2 und 3. Dies [,1]ist die vollständige Übereinstimmung. [,2:3]ist die erfassten Gruppen.
Kent Johnson

50

gsub macht dies anhand Ihres Beispiels:

gsub("\\((.*?) :: (0\\.[0-9]+)\\)","\\1 \\2", "(sometext :: 0.1231313213)")
[1] "sometext 0.1231313213"

Sie müssen die \ s in den Anführungszeichen doppelt maskieren, damit sie für den regulären Ausdruck funktionieren.

Hoffe das hilft.


Eigentlich muss ich die erfassten Teilzeichenfolgen herausziehen, um sie in einen data.frame einzufügen. Aber wenn ich Ihre Antwort betrachte, könnte ich gsub und ein paar strsplits verketten, um das zu bekommen, was ich will, vielleicht: strsplit (strsplit (gsub (regex, "\\ 1 :: \\ 2 ::::", str ), "::::") [[1]], "::")
Daniel Dickison

8
Toll. Die R- gsubManpage benötigt dringend ein Beispiel, das zeigt, dass Sie '\\ 1' benötigen, um einer Capture-Gruppenreferenz zu entkommen.
smci

33

Versuchen Sie regmatches()und regexec():

regmatches("(sometext :: 0.1231313213)",regexec("\\((.*?) :: (0\\.[0-9]+)\\)","(sometext :: 0.1231313213)"))
[[1]]
[1] "(sometext :: 0.1231313213)" "sometext"                   "0.1231313213"

3
Vielen Dank für die Vanille R-Lösung und für den Hinweis, regmatchesden ich noch nie gesehen habe
Andy

Warum müssten Sie die Zeichenfolge zweimal schreiben?
Stefano Borini

@StefanoBorini regexecgibt eine Liste zurück, die nur Informationen zum Speicherort der Übereinstimmungen enthält. Daher regmatchesmuss der Benutzer die Zeichenfolge angeben , zu der die Übereinstimmungsliste gehört.
RTbecard

19

gsub () kann dies tun und nur die Erfassungsgruppe zurückgeben:

Damit dies funktioniert, müssen Sie jedoch explizit Elemente außerhalb Ihrer Erfassungsgruppe auswählen, wie in der Hilfe zu gsub () angegeben.

(...) Elemente von Zeichenvektoren 'x', die nicht ersetzt werden, werden unverändert zurückgegeben.

Wenn Ihr zu wählender Text also in der Mitte einer Zeichenfolge liegt, sollten Sie durch Hinzufügen von. * Vor und nach der Erfassungsgruppe nur den Text zurückgeben können.

gsub(".*\\((.*?) :: (0\\.[0-9]+)\\).*","\\1 \\2", "(sometext :: 0.1231313213)") [1] "sometext 0.1231313213"


4

Ich mag Perl-kompatible reguläre Ausdrücke. Wahrscheinlich macht es auch jemand anderes ...

Hier ist eine Funktion, die Perl-kompatible reguläre Ausdrücke ausführt und mit der Funktionalität von Funktionen in anderen Sprachen übereinstimmt, an die ich gewöhnt bin:

regexpr_perl <- function(expr, str) {
  match <- regexpr(expr, str, perl=T)
  matches <- character(0)
  if (attr(match, 'match.length') >= 0) {
    capture_start <- attr(match, 'capture.start')
    capture_length <- attr(match, 'capture.length')
    total_matches <- 1 + length(capture_start)
    matches <- character(total_matches)
    matches[1] <- substr(str, match, match + attr(match, 'match.length') - 1)
    if (length(capture_start) > 1) {
      for (i in 1:length(capture_start)) {
        matches[i + 1] <- substr(str, capture_start[[i]], capture_start[[i]] + capture_length[[i]] - 1)
      }
    }
  }
  matches
}

3

So habe ich dieses Problem umgangen. Ich habe zwei separate reguläre Ausdrücke verwendet, um die erste und die zweite Erfassungsgruppe abzugleichen, zwei gregexprAufrufe auszuführen und dann die übereinstimmenden Teilzeichenfolgen herauszuziehen:

regex.string <- "(?<=\\().*?(?= :: )"
regex.number <- "(?<= :: )\\d\\.\\d+"

match.string <- gregexpr(regex.string, str, perl=T)[[1]]
match.number <- gregexpr(regex.number, str, perl=T)[[1]]

strings <- mapply(function (start, len) substr(str, start, start+len-1),
                  match.string,
                  attr(match.string, "match.length"))
numbers <- mapply(function (start, len) as.numeric(substr(str, start, start+len-1)),
                  match.number,
                  attr(match.number, "match.length"))

+1 für einen Arbeitscode. Ich würde jedoch lieber einen schnellen Shell-Befehl von R ausführen und einen Bash- expr "xyx0.0023xyxy" : '[^0-9]*\([.0-9]\+\)'
Einzeiler

3

Lösung mit strcaptureaus dem utils:

x <- c("key1 :: 0.01",
       "key2 :: 0.02")
strcapture(pattern = "(.*) :: (0\\.[0-9]+)",
           x = x,
           proto = list(key = character(), value = double()))
#>    key value
#> 1 key1  0.01
#> 2 key2  0.02

2

Wie im stringrPaket vorgeschlagen, kann dies entweder mit str_match()oder erreicht werden str_extract().

Angepasst aus dem Handbuch:

library(stringr)

strings <- c(" 219 733 8965", "329-293-8753 ", "banana", 
             "239 923 8115 and 842 566 4692",
             "Work: 579-499-7527", "$1000",
             "Home: 543.355.3679")
phone <- "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})"

Extrahieren und Kombinieren unserer Gruppen:

str_extract_all(strings, phone, simplify=T)
#      [,1]           [,2]          
# [1,] "219 733 8965" ""            
# [2,] "329-293-8753" ""            
# [3,] ""             ""            
# [4,] "239 923 8115" "842 566 4692"
# [5,] "579-499-7527" ""            
# [6,] ""             ""            
# [7,] "543.355.3679" ""   

Anzeigen von Gruppen mit einer Ausgabematrix (wir interessieren uns für Spalten 2+):

str_match_all(strings, phone)
# [[1]]
#      [,1]           [,2]  [,3]  [,4]  
# [1,] "219 733 8965" "219" "733" "8965"
# 
# [[2]]
#      [,1]           [,2]  [,3]  [,4]  
# [1,] "329-293-8753" "329" "293" "8753"
# 
# [[3]]
#      [,1] [,2] [,3] [,4]
# 
# [[4]]
#      [,1]           [,2]  [,3]  [,4]  
# [1,] "239 923 8115" "239" "923" "8115"
# [2,] "842 566 4692" "842" "566" "4692"
# 
# [[5]]
#      [,1]           [,2]  [,3]  [,4]  
# [1,] "579-499-7527" "579" "499" "7527"
# 
# [[6]]
#      [,1] [,2] [,3] [,4]
# 
# [[7]]
#      [,1]           [,2]  [,3]  [,4]  
# [1,] "543.355.3679" "543" "355" "3679"

Was ist mit 842 566 4692
Ferroao

Vielen Dank, dass Sie die Lücke geschlossen haben. Korrigiert mit dem _allSuffix für die relevanten stringrFunktionen.
Megatron

0

Dies kann mit dem Paket unglue erfolgen , wobei das Beispiel aus der ausgewählten Antwort entnommen wird:

# install.packages("unglue")
library(unglue)

s <- c("(sometext :: 0.1231313213)", "(moretext :: 0.111222)")
unglue_data(s, "({x} :: {y})")
#>          x            y
#> 1 sometext 0.1231313213
#> 2 moretext     0.111222

Oder ausgehend von einem Datenrahmen

df <- data.frame(col = s)
unglue_unnest(df, col, "({x} :: {y})",remove = FALSE)
#>                          col        x            y
#> 1 (sometext :: 0.1231313213) sometext 0.1231313213
#> 2     (moretext :: 0.111222) moretext     0.111222

Sie können den rohen regulären Ausdruck aus dem nicht klebenden Muster erhalten, optional mit der benannten Erfassung:

unglue_regex("({x} :: {y})")
#>             ({x} :: {y}) 
#> "^\\((.*?) :: (.*?)\\)$"

unglue_regex("({x} :: {y})",named_capture = TRUE)
#>                     ({x} :: {y}) 
#> "^\\((?<x>.*?) :: (?<y>.*?)\\)$"

Weitere Informationen: https://github.com/moodymudskipper/unglue/blob/master/README.md

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.