ChatGPT解决这个技术问题 Extra ChatGPT

在R中的其他两个字符串之间提取一个字符串

我试图找到一种简单的方法来提取出现在两个已知子字符串之间的未知子字符串(可能是任何东西)。例如,我有一个字符串:

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"

我当然可以剥离已知字符串,以隔离我需要的子字符串,但我认为应该有一种更简洁的方法来使用正确的正则表达式。

使用this奇妙的功能regcapturedmatches(test, gregexpr('STR1 (.+?) STR2', test, perl = TRUE))

K
Kim

您可以将 str_matchSTR1 (.*?) STR2 一起使用(注意空格是“有意义的”,如果您只想匹配 STR1STR2 之间的任何内容,请使用 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"

有用!问号的目的是什么?没有它似乎也可以工作。
这里的 ?lazy(非贪婪)量词的一部分。它匹配尽可能少的字符,而 * 将匹配尽可能多的字符。因此,STR1 .*? STR2 正则表达式匹配 STR1 xx STR2,而 STR1 .* STR2 将匹配 STR1 xx STR2 zzz STR2。如果您希望输入中有多个匹配项,则此处必须使用惰性量词。另外,仅供参考:如果 STR1STR2 之间的字符串部分可能包含换行符,则需要在模式前面加上 (?s)"(?s)STR1 (.*?) STR2"
@Wiktor:你能解释一下为什么 str_match 输出在矩阵中吗?这似乎很不方便,尤其是当大多数人想要的唯一输出是 [,2]
@Nettle 我不同意,因为如果有人只想要 [,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 一起使用的模式效率更高。
我也写了一个通用的 article about extracting strings between two strings with regex,如果您在解决当前类似问题时遇到问题,请随时阅读。
U
Ulises Rosas-Puchuri

这是使用基础 R 的另一种方法

a<-" anything goes here, STR1 GET_ME STR2, anything goes here"

gsub(".*STR1 (.+) STR2.*", "\\1", a)

输出:

[1] "GET_ME"

你能解释一下\\1吗?
R
Ronak Shah

另一种选择是使用 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”之间。


m
moodymudskipper

我们可以使用 {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

如果我们想使用任何变量来代替 STR1 和 STR2,我们该怎么做。假设我将 STR1 分配给 a 并将 STR2 分配给 b,现在我们如何使用正则表达式来提取 a 和 b 之间的字符串
您可以使用 sprintf("{left}, %s {x} %s, {right}", a, b)paste0("{left}, ", a, " {x} ", b, ", {right}") 代替 "{left}, STR1 {x} STR2, {right}"