在字符串中提取名称的某些部分

时间:2016-05-13 10:54:52

标签: r

我试图在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。 感谢您的任何提示。

3 个答案:

答案 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)

regexprregmatches与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"