R中的正则表达式组捕获具有多个捕获组

问题描述 投票:85回答:8

在R中,是否可以从正则表达式匹配中提取组捕获?据我所知,没有一个grepgreplregexprgregexprsubgsub都没有回归。

我需要从编码的字符串中提取键值对:

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

我总是可以做多个全匹配greps,或做一些外部(非R)处理,但我希望我能在R中完成所有操作。是否有一个功能或包提供这样的功能来执行此操作?

regex r capture capture-group
8个回答
110
投票

来自str_match()包的stringr将会这样做。它返回一个字符矩阵,匹配中的每个组都有一列(整个匹配一个):

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

43
投票

gsub从你的例子做到这一点:

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

你需要双重转义引号中的\ s然后它们适用于正则表达式。

希望这可以帮助。


29
投票

试试regmatches()regexec()

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

18
投票

gsub()可以执行此操作并仅返回捕获组:

但是,为了使其正常工作,您必须显式选择gsub()帮助中提到的捕获组外部的元素。

(...)未替换的字符向量'x'的元素将保持不变。

因此,如果要选择的文本位于某个字符串的中间,则在捕获组之前和之后添加。*应允许您仅返回它。

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


4
投票

我喜欢perl兼容的正则表达式。也许其他人也会这样做......

这是一个函数,它执行perl兼容的正则表达式,并匹配我以前使用的其他语言中的函数的功能:

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
投票

这就是我最终解决这个问题的方法。我使用两个单独的正则表达式匹配第一个和第二个捕获组并运行两个qazxsw poi调用,然后拉出匹配的子串:

gregexpr

2
投票

来自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")) strcapture解决方案:

utils

2
投票

正如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 包中所建议的那样,这可以使用stringrstr_match()来实现。

改编自手册:

str_extract()

提取和组合我们的团队:

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})"

指示具有输出矩阵的组(我们对第2列感兴趣):

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" ""   
© www.soinside.com 2019 - 2024. All rights reserved.