用于正则表达式捕获组的R函数是什么?

Bal*_*ury 4 regex r

我正在R中进行一些文本争论,对于特定的提取,我需要使用捕获组.由于某种原因,我熟悉的base/stringr函数似乎不支持捕获组:

str_extract("abcd123asdc", pattern = "([0-9]{3}).+$") 
# Returns: "123asdc"

stri_extract(str = "abcd123asdc", regex = "([0-9]{3}).+$")
# Returns: "123asdc"

grep(x = "abcd123asdc", pattern = "([0-9]{3}).+$", value = TRUE)
# Returns: "abcd123asdc"
Run Code Online (Sandbox Code Playgroud)

通常谷歌搜索"R捕获组正则表达式"没有给出解决这个问题的任何有用的点击.我错过了什么,或者是R中没有实现的捕获组?

编辑:所以在尝试解决方案中建议的解决方案,这是一个小例子,它失败了我的情况.

请注意,这是来自enron电子邮件数据集的文本,因此不包含敏感信息.

txt <- "Message-ID: <24216240.1075855687451.JavaMail.evans@thyme>
Date: Wed, 18 Oct 2000 03:00:00 -0700 (PDT)
From: phillip.allen@enron.com
To: leah.arsdall@enron.com
Subject: Re: test
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-From: Phillip K Allen
X-To: Leah Van Arsdall
X-cc: 
X-bcc: 
X-Folder: \\Phillip_Allen_Dec2000\\Notes Folders\\sent mail   
X-Origin: Allen-P
X-FileName: pallen.nsf

test successful.  way to go!!!"

sub("X-FileName:.+\n\n([\\W\\w]+)$", "\\1", txt)
# Returns all of "txt", not the capture group
Run Code Online (Sandbox Code Playgroud)

既然我们只有一个捕获组,那么不应该将"\ 1"捕获它吗?我用在线正则表达式测试器测试了正则表达式,它应该正常工作.还尝试了\n和\n用于换行.有任何想法吗?

Wik*_*żew 7

完成工作

您可以始终使用或使用stringr提取捕获组:str_matchstr_match_all

> result <- str_match(txt, "X-FileName:.+\n\n(?s)(.+)$")
> result[,2]
[1] "test successful.  way to go!!!"
Run Code Online (Sandbox Code Playgroud)

图案细节:

  • X-FileName: - 一个文字子串
  • .+ - 除了换行符之外的任何1个字符(因为在ICU正则表达式中,点与换行符不匹配)
  • \n\n - 2个换行符号
  • (?s)- 内联DOTALL修饰符(现在,.右边出现的匹配换行符)
  • (.+) - 第1组捕获任何1个以上的字符(包括换行符)
  • $ - 字符串的结尾.

或者你可以使用基础R regmatchesregexec:

> result <- regmatches(txt, regexec("X-FileName:[^\n]+\n\n(.+)$", txt))
> result[[1]][2]
[1] "test successful.  way to go!!!"
Run Code Online (Sandbox Code Playgroud)

查看在线R演示.在这里,使用TRE正则表达式(regexec不幸的是,不能使用PCRE正则表达式),因此.将匹配包括换行符的任何字符,因此,模式将如下所示X-FileName:[^\n]+\n\n(.+)$:

  • X-FileName: - 一个文字字符串
  • [^\n]+ - 换行以外的1个字符
  • \n\n - 2个换行符
  • (.+) - 任何1个字符(包括换行符),尽可能多,最多
  • $ - 字符串的结尾.

sub也可以考虑一个选项:

sub(".*X-FileName:[^\n]+\n\n", "", txt)
[1] "test successful.  way to go!!!"
Run Code Online (Sandbox Code Playgroud)

这个R演示.在这里,.*匹配任何0+字符,尽可能多(所有字符串),然后回溯以查找X-FileName:子字符串,[^\n]+匹配除换行符之外的1 +字符,然后\n\n匹配2个换行符.

比较性能

考虑到hwnd的评论,我在sub上面添加了一个基于TRE正则表达式的选项,它似乎是建议的所有4个选项中最快的,str_match几乎和我上面的sub代码一样快:

library(microbenchmark)

f1 <- function(text) { return(str_match(txt, "X-FileName:.+\n\n(?s)(.+)$")[,2]) }
f2 <- function(text) { return(regmatches(txt, regexec("X-FileName:[^\n]+\n\n(.+)$", txt))[[1]][2]) }
f3 <- function(text) { return(sub('(?s).*X-FileName:[^\n]+\\R+', '', txt, perl=TRUE)) }
f4 <- function(text) { return(sub('.*X-FileName:[^\n]+\n\n', '', txt)) }

> test <- microbenchmark( f1(txt), f2(txt), f3(txt), f4(txt), times = 500000 )
> test
Unit: microseconds
    expr    min     lq     mean median     uq       max neval  cld
 f1(txt) 21.130 24.451 28.08150 27.168 28.677 53796.565 5e+05  b  
 f2(txt) 29.280 32.903 37.46800 35.318 37.431 54556.635 5e+05   c 
 f3(txt) 57.655 59.466 63.36906 60.674 61.881  1651.448 5e+05    d
 f4(txt) 22.036 23.545 25.56820 24.451 25.356  1660.504 5e+05 a   
Run Code Online (Sandbox Code Playgroud)