captura grupo regex em R com vários grupos de captura-
-
11-09-2019 - |
Pergunta
Em R, é possível extrair captura de grupo a partir de uma expressão regular? Tanto quanto eu posso dizer, nenhum dos grep
, grepl
, regexpr
, gregexpr
, sub
, ou gsub
voltar a captura do grupo.
Eu preciso extrair pares chave-valor de cordas que são codificados assim:
\((.*?) :: (0\.[0-9]+)\)
Eu sempre pode apenas fazer várias greps full-jogo, ou fazer algum processamento externo (não-R), mas eu estava esperando que eu possa fazer tudo dentro R. Existe uma função ou um pacote que fornece tal função para fazer isso?
Solução
str_match()
, do href="http://cran.r-project.org/web/packages/stringr/index.html" rel="noreferrer"> stringr
pacote , vai fazer isso . Ele retorna uma matriz de caracteres com uma coluna para cada grupo durante o jogo (e um para toda a partida):
> 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"
Outras dicas
gsub faz isso, a partir do seu exemplo:
gsub("\\((.*?) :: (0\\.[0-9]+)\\)","\\1 \\2", "(sometext :: 0.1231313213)")
[1] "sometext 0.1231313213"
você precisa dobrar escapar o \ s nas citações em seguida, eles trabalham para a regex.
Espero que isso ajude.
regmatches()
Experimente e regexec()
:
regmatches("(sometext :: 0.1231313213)",regexec("\\((.*?) :: (0\\.[0-9]+)\\)","(sometext :: 0.1231313213)"))
[[1]]
[1] "(sometext :: 0.1231313213)" "sometext" "0.1231313213"
gsub () pode fazer isso e retornar somente o grupo de captura:
No entanto, para que isso funcione, você deve selecionar explicitamente elementos fora do seu grupo de captura, como mencionado na ajuda gsub ().
(...) elementos de caráter vetores 'x' que não são substituídos serão devolvidos inalterada.
Portanto, se seu texto a ser selecionado mentiras no meio de alguma corda, acrescentando. * Antes e depois do grupo de captura deve permitir que você devolvê-lo apenas.
gsub(".*\\((.*?) :: (0\\.[0-9]+)\\).*","\\1 \\2", "(sometext :: 0.1231313213)")
[1] "sometext 0.1231313213"
Eu gosto de expressões regulares compatíveis com Perl. Provavelmente alguém faz também ...
Aqui está uma função que faz perl expressões regulares compatíveis e combina a funcionalidade de funções em outras línguas que eu estou acostumado a:
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
}
Isto é como eu acabei trabalhando em torno deste problema. Eu usei duas expressões regulares separadas para coincidir com o primeiro e segundo grupos de captura e executar duas chamadas gregexpr
, em seguida, puxe os substrings correspondentes:
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"))
Solução com strcapture
do 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
Como sugerido na href="https://cran.r-project.org/web/packages/stringr/index.html" rel="nofollow noreferrer"> stringr
pacote , isso pode ser conseguida utilizando qualquer um ou str_match()
str_extract()
.
Adaptado do manual:
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})"
extrair e combinar os nossos grupos:
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" ""
grupos Indicando com uma matriz de saída (Nós estamos interessados ??em colunas 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"