r语言 - 用于选择第二次出现的字符的RegEx语法



我有一个相对简单的问题,但不能找出正确的语法在RegEx。我有多个实验名称作为各种格式的字符串,例如SEF001DT45BV004MF.

我要做的是选择在数值(DT)之后出现的第二个字母。和

我明白了[A-Z]{2}只解决了我问题的一半。如何得到合适的子字符串?

一个可能的解决方案,基于stringr::str_extract和环顾四周:

library(stringr)
strings <- c("SEF001DT45", "BV004MF")
str_extract(strings, "(?<=\d)[:upper:]{2}")
#> [1] "DT" "MF"

Base R:

# Using capture groups:
gsub(
".*\d{2}(\w{2}).*",
"\1",
x
)
# Input data:
x <- c(
'SEF001DT45',
'BV004MF'
)

TLDR:通常,您可以使用以下命令之一获得第二次出现的PATTERN

sub('.*?PATTERN.*?(PATTERN).*', '\1', x)
stringr::str_match(x, 'PATTERN.*?(PATTERN)')[,2]
regmatches(x, regexpr('PATTERN.*?\KPATTERN', x, perl=TRUE))

可以使用

x <- c('SEF001DT45','BV004MF')
sub('.*?[A-Z]{2}.*?([A-Z]{2}).*', '\1', x)
## => [1] "DT" "MF"

参见R的在线演示和正则表达式的演示。这里的重点是匹配模式的第二次出现,捕获它,然后匹配其余的,并替换为捕获组值的反向引用。

注意,sub将执行单个搜索和替换操作,这很好,因为这里的正则表达式需要整个字符串匹配。

细节:

  • .*?-任何零或更多字符越少越好
  • [A-Z]{2}-两个大写ASCII字母
  • .*?-任何零或更多字符尽可能少
  • ([A-Z]{2})-组1 (1指该组值):两个大写ASCII字母
  • .*-任何零或更多字符尽可能多。

您可以使用stringr::str_match:

使用更简单的正则表达式来实现这一点
x <- c('SEF001DT45','BV004MF')
library(stringr)
results <- stringr::str_match(x, '[A-Z]{2}.*?([A-Z]{2})')
results[,2] ## Get Group 1 values

查看这个R演示。

或者,regmatches/regexpr在R底:

x <- c('SEF001DT45','BV004MF')
results <- regmatches(x, regexpr('[A-Z]{2}.*?\K[A-Z]{2}', x, perl=TRUE))
results

查看这个R演示。

在这里,[A-Z]{2}.*?\K[A-Z]{2}查找前两个大写ASCII字母,然后尽可能少地匹配任何零个或多个字符(由于使用了PCRE引擎,因此换行符除外),然后K丢弃匹配的文本,模式末尾的[A-Z]{2}匹配第二次出现的两个字母块。regexpr只找到第一个匹配项。

另一个基本R技巧是strsplit

> sapply(strsplit(s, split = "\d+"), `[[`, 2)
[1] "DT" "MF"

gsub

> gsub("^.*?(?<=\d)(\D+).*", "\1", s, perl = TRUE)
[1] "DT" "MF"

Maybe:

s <- c("SEF001DT45", "BV004MF")
sub("[A-Z]+\d+([A-Z]{2}).*", "\1", s)
#sub("[A-Z]+[0-9]+([A-Z]{2}).*", "\1", s) #Alternative
#[1] "DT" "MF"

其中[A-Z]匹配字符,\d匹配数字,[A-Z]{2}匹配两个字符,.*匹配其余部分。
对于(),选择用\1插入的内容。
或者更严格的两个字母的第二次出现:

sub(".*?[A-Z]{2}[0-9]+([A-Z]{2}).*", "\1", s)
#[1] "DT" "MF"

当只提取第一个数字后面的两个字符时:

regmatches(s, regexpr("(?<=\d)[A-Z]{2}", s, perl=TRUE))
#[1] "DT" "MF"

最新更新