我试图找到一种简单的方法来提取出现在两个已知子字符串之间的未知子字符串(可能是任何东西)。例如,我有一个字符串:
a<-" anything goes here, STR1 GET_ME STR2, anything goes here"
我需要提取 STR1 和 STR2 之间的字符串 GET_ME
(没有空格)。
我正在尝试 str_extract(a, "STR1 (.+) STR2")
,但我得到了整场比赛
[1] "STR1 GET_ME STR2"
我当然可以剥离已知字符串,以隔离我需要的子字符串,但我认为应该有一种更简洁的方法来使用正确的正则表达式。
regcapturedmatches(test, gregexpr('STR1 (.+?) STR2', test, perl = TRUE))
您可以将 str_match
与 STR1 (.*?) STR2
一起使用(注意空格是“有意义的”,如果您只想匹配 STR1
和 STR2
之间的任何内容,请使用 STR1(.*?)STR2
,或使用 STR1\\s*(.*?)\\s*STR2
来修剪您的值需要)。如果出现多次,请使用 str_match_all
。
此外,如果您需要匹配跨越换行符/换行符的字符串,请在模式开头添加 (?s)
:(?s)STR1(.*?)STR2
/ (?s)STR1\\s*(.*?)\\s*STR2
。
library(stringr)
a <- " anything goes here, STR1 GET_ME STR2, anything goes here"
res <- str_match(a, "STR1\\s*(.*?)\\s*STR2")
res[,2]
[1] "GET_ME"
使用 base R regexec
的另一种方法(获得第一个匹配项):
test <- " anything goes here, STR1 GET_ME STR2, anything goes here STR1 GET_ME2 STR2"
pattern <- "STR1\\s*(.*?)\\s*STR2"
result <- regmatches(test, regexec(pattern, test))
result[[1]][2]
[1] "GET_ME"
这是使用基础 R 的另一种方法
a<-" anything goes here, STR1 GET_ME STR2, anything goes here"
gsub(".*STR1 (.+) STR2.*", "\\1", a)
输出:
[1] "GET_ME"
\\1
吗?
另一种选择是使用 qdapRegex::ex_between
提取左右边界之间的字符串
qdapRegex::ex_between(a, "STR1", "STR2")[[1]]
#[1] "GET_ME"
它也适用于多次出现
a <- "anything STR1 GET_ME STR2, anything goes here, STR1 again get me STR2"
qdapRegex::ex_between(a, "STR1", "STR2")[[1]]
#[1] "GET_ME" "again get me"
或多个左右边界
a <- "anything STR1 GET_ME STR2, anything goes here, STR4 again get me STR5"
qdapRegex::ex_between(a, c("STR1", "STR4"), c("STR2", "STR5"))[[1]]
#[1] "GET_ME" "again get me"
第一次捕获在“STR1”和“STR2”之间,而第二次在“STR4”和“STR5”之间。
我们可以使用 {unglue},在这种情况下我们根本不需要正则表达式:
library(unglue)
unglue::unglue_vec(
" anything goes here, STR1 GET_ME STR2, anything goes here",
"{}STR1 {x} STR2{}")
#> [1] "GET_ME"
{}
匹配任何内容而不保留它,{x}
捕获其匹配项(可以使用除 x
之外的任何变量。语法"{}STR1 {x} STR2{}"
是:"{=.*?}STR1 {x=.*?} STR2{=.*?}"
如果你也想提取侧面,你可以这样做:
unglue::unglue_data(
" anything goes here, STR1 GET_ME STR2, anything goes here",
"{left}, STR1 {x} STR2, {right}")
#> left x right
#> 1 anything goes here GET_ME anything goes here
sprintf("{left}, %s {x} %s, {right}", a, b)
或 paste0("{left}, ", a, " {x} ", b, ", {right}")
代替 "{left}, STR1 {x} STR2, {right}"
?
是 lazy(非贪婪)量词的一部分。它匹配尽可能少的字符,而*
将匹配尽可能多的字符。因此,STR1 .*? STR2
正则表达式匹配STR1 xx STR2
,而STR1 .* STR2
将匹配STR1 xx STR2 zzz STR2
。如果您希望输入中有多个匹配项,则此处必须使用惰性量词。另外,仅供参考:如果STR1
和STR2
之间的字符串部分可能包含换行符,则需要在模式前面加上(?s)
:"(?s)STR1 (.*?) STR2"
。str_match
输出在矩阵中吗?这似乎很不方便,尤其是当大多数人想要的唯一输出是[,2]
[,2]
,他们应该只使用regmatches(a, regexpr("STR1\\s*\\K.*?(?=\\s*STR2)", a, perl=TRUE))
。使用stringr
,也可以使用像str_extract_all(a, "(?s)(?<=STR1\\s{0,1000}).*?(?=\\s*STR2)")
这样的模式(尽管由于某种原因,空格仍然包含在匹配中,而且相当 hacky)。当您需要返回所有匹配和捕获时,str_match
是救命稻草。此外,可以与str_match
一起使用的模式效率更高。