Czy w języku R można wyodrębnić przechwytywanie grupy z dopasowania wyrażenia regularnego? O ile mi wiadomo, żaden z grep
, grepl
, regexpr
, gregexpr
, sub
, lub gsub
zwrócić przechwytuje grupowych.
Muszę wyodrębnić pary klucz-wartość z ciągów, które są zakodowane w ten sposób:
\((.*?) :: (0\.[0-9]+)\)
Zawsze mogę po prostu wykonać wiele pełnych dopasowań greps lub wykonać pewne przetwarzanie zewnętrzne (inne niż R), ale miałem nadzieję, że mogę to wszystko zrobić w R. Czy istnieje funkcja lub pakiet, który zapewnia taką funkcję, aby to zrobić?
regex
r
capture
capture-group
Daniel Dickison
źródło
źródło
str_match_all()
aby dopasować wszystkie grupy w wyrażeniu regularnym[,1]
to pełne dopasowanie.[,2:3]
to przechwycone grupy.gsub robi to, z twojego przykładu:
gsub("\\((.*?) :: (0\\.[0-9]+)\\)","\\1 \\2", "(sometext :: 0.1231313213)") [1] "sometext 0.1231313213"
musisz dwukrotnie zmienić znak \ s w cudzysłowach, a następnie działają one z wyrażeniem regularnym.
Mam nadzieję że to pomoże.
źródło
gsub
podręcznika R bardzo potrzebuje przykładu pokazującego, że potrzebujesz '\\ 1', aby uniknąć odniesienia do grupy przechwytywania.Spróbuj
regmatches()
iregexec()
:regmatches("(sometext :: 0.1231313213)",regexec("\\((.*?) :: (0\\.[0-9]+)\\)","(sometext :: 0.1231313213)")) [[1]] [1] "(sometext :: 0.1231313213)" "sometext" "0.1231313213"
źródło
regmatches
czego nigdy wcześniej nie widziałemregexec
zwraca listę zawierającą informacje dotyczące tylko lokalizacji dopasowań, dlategoregmatches
wymaga od użytkownika podania ciągu, do którego należała lista dopasowań.gsub () może to zrobić i zwrócić tylko grupę przechwytywania:
Jednak aby to zadziałało, musisz jawnie wybrać elementy spoza grupy przechwytywania, jak wspomniano w pomocy gsub ().
Jeśli więc tekst, który ma zostać zaznaczony, znajduje się w środku jakiegoś ciągu, dodanie. * Przed i po grupie przechwytywania powinno pozwolić tylko na jego zwrócenie.
gsub(".*\\((.*?) :: (0\\.[0-9]+)\\).*","\\1 \\2", "(sometext :: 0.1231313213)") [1] "sometext 0.1231313213"
źródło
Lubię wyrażenia regularne zgodne z Perlem. Prawdopodobnie ktoś inny też ...
Oto funkcja, która obsługuje wyrażenia regularne zgodne z Perlem i dopasowuje funkcjonalność funkcji w innych językach, do których jestem przyzwyczajony:
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 }
źródło
W ten sposób udało mi się rozwiązać ten problem. Użyłem dwóch oddzielnych wyrażeń regularnych, aby dopasować pierwszą i drugą grupę przechwytywania i uruchomiłem dwa
gregexpr
wywołania, a następnie wyciągnąłem dopasowane podciągi: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"))
źródło
expr "xyx0.0023xyxy" : '[^0-9]*\([.0-9]\+\)'
Rozwiązanie z
strcapture
odutils
: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
źródło
Jak zasugerowano w
stringr
pakiecie, można to osiągnąć za pomocąstr_match()
lubstr_extract()
.Na podstawie instrukcji:
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})"
Wyodrębnianie i łączenie naszych grup:
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" ""
Wskazanie grup z macierzą wyjściową (interesują nas kolumny 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"
źródło
_all
przyrostka dla odpowiednichstringr
funkcji.Można to zrobić za pomocą odklejenia pakietu , biorąc przykład z wybranej odpowiedzi:
# 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
Lub zaczynając od ramki danych
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
możesz pobrać surowe wyrażenie regularne ze wzoru unglue, opcjonalnie z nazwanym przechwytywaniem:
unglue_regex("({x} :: {y})") #> ({x} :: {y}) #> "^\\((.*?) :: (.*?)\\)$" unglue_regex("({x} :: {y})",named_capture = TRUE) #> ({x} :: {y}) #> "^\\((?<x>.*?) :: (?<y>.*?)\\)$"
Więcej informacji: https://github.com/moodymudskipper/unglue/blob/master/README.md
źródło