我有一个相对简单的问题,但不能找出正确的语法在RegEx。我有多个实验名称作为各种格式的字符串,例如SEF001DT45或BV004MF.
我要做的是选择在数值(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"