wake-up-neo.com

Regex-Gruppenerfassung in R mit mehreren Erfassungsgruppen

Ist es in R möglich, die Gruppenerfassung aus einer Übereinstimmung mit regulären Ausdrücken zu extrahieren? Soweit ich das beurteilen kann, gibt es keine von grep, grepl, regexpr, gregexpr, sub oder gsub gibt die Gruppenerfassungen zurück.

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

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

Ich kann immer nur mehrere vollständige Match-Greps ausführen oder einige externe (nicht-R-) Verarbeitungsschritte ausfü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?

87
Daniel Dickison

str_match() aus dem stringr -Paket erledigt dies. Es wird eine Zeichenmatrix mit einer Spalte für jede Gruppe in der Übereinstimmung (und eine 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"    
110
Kent Johnson

gsub macht das, aus deinem Beispiel:

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

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

Hoffe das hilft.

44

Versuchen Sie regmatches() und regexec():

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

gsub () kann dies und gibt nur die Erfassungsgruppe zurück:

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

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

Wenn sich Ihr auszuwählender Text also in der Mitte einer Zeichenfolge befindet, sollten Sie beim Hinzufügen von. * Vor und nach der Erfassungsgruppe nur diese Zeichenfolge zurückgeben können.

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

18
cashoes

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

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

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
}
4
ruffbytes

So habe ich dieses Problem umgangen. Ich habe zwei separate reguläre Ausdrücke verwendet, um die erste und die zweite Erfassungsgruppe abzugleichen, zwei gregexpr -Aufrufe ausgeführt und dann die übereinstimmenden Teilzeichenfolgen abgerufen:

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"))
3
Daniel Dickison

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

Aus dem Handbuch übernommen:

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"
2
Megatron

Lösung mit strcapture aus 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
Artem Klevtsov