我试图在DF
DF
a b
a.b.c_tot 1
b.c.d_tot 2
d.e.g_tot 3
我需要在.
和_tot
之间提取字母,以便
DF
a b c
a.b.c_tot 1 c
b.c.d_tot 2 d
d.e.g_tot 3 g
我想可以用sub
来完成,因为我今天已经学会了如何在第一个.
之前提取字母,但是如何提取"中间"部分名称?
我正在阅读sub
解释和帮助,但我的所有试验都只会将a
的全名复制到c
。
感谢您的任何提示。
答案 0 :(得分:4)
我们可以调用sub()
来匹配整个字符串,从(1)任意数量的任何字符开始,然后(2)一个文字点,然后(3)使用捕获组捕获以下字符,然后(4)文字_tot
。然后我们可以使用\1
反向引用原子(根据R&#39的字符串编码规则使用反斜杠正确反斜杠转义)来用捕获的字符替换整个字符串。
DF$c <- sub('^.*\\.(.)_tot$','\\1',DF$a);
DF;
## a b c
## 1 a.b.c_tot 1 c
## 2 b.c.d_tot 2 d
## 3 d.e.g_tot 3 g
是的,我看到了问题;如果DF$a
包含与预期模式不匹配的值,则sub()
调用会将它们传递到新的DF$c
列。这是使用Perl branch reset功能的hacky解决方案:
DF <- data.frame(a=c('a.b.c_tot','b.c.d_tot','d.e.g_tot','non-matching'),b=c(1L,2L,3L,4L),stringsAsFactors=F);
DF$c <- sub(perl=T,'(?|^.*\\.(.)_tot$|^.*$())','\\1',DF$a);
DF;
## a b c
## 1 a.b.c_tot 1 c
## 2 b.c.d_tot 2 d
## 3 d.e.g_tot 3 g
## 4 non-matching 4
这是一个更好的解决方案,包括提前将正则表达式存储在变量中,并使用grepl()
和replace()
在调用sub()
之前用NA替换非匹配值:
re <- '^.*\\.(.)_tot$';
DF$c <- sub(re,'\\1',replace(DF$a,!grepl(re,DF$a),NA));
DF;
## a b c
## 1 a.b.c_tot 1 c
## 2 b.c.d_tot 2 d
## 3 d.e.g_tot 3 g
## 4 non-matching 4 <NA>
答案 1 :(得分:2)
将regexpr
和regmatches
与lookbehind和lookahead regex一起使用。
x <- c("a.b.c_tot", "b.c.d_tot", "d.e.g_tot")
regmatches(x, regexpr("(?<=\\.).(?=_tot)", x, perl = TRUE))
#[1] "c" "d" "g"
答案 2 :(得分:2)
我们可以使用str_extract
library(stringr)
DF$c <- str_extract(DF$a, "\\w(?=_tot)")
DF$c
#[1] "c" "d" "g"