2016-05-13 128 views
0

我試着在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

您可以使用'子()'函數,如果要提取那封信。 –

+1

謝謝,substring()完成了這項工作!看起來好像比分:) :) – HoHoHo

回答

4

我們可以調用sub()來匹配整個字符串,從(1)任意數量的任何字符開始,然後(2)一個字面點,然後(3)使用捕獲組來捕獲以下字符,然後(4 )字面意思_tot。然後,我們可以使用\1反向引用原子(根據R的字符串編碼規則將反斜槓正確反斜槓轉義)用捕獲的字符替換整個字符串。

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特徵的哈克溶液:

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()以取代NA不匹配的值調用sub()之前:

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> 
+0

不幸的是,它也返回了我的全名。 – HoHoHo

+0

謝謝,現在正在工作。是的,這是我的錯。 – HoHoHo

2

使用regexprregmatches與回顧後和前瞻正則表達式。

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

我們可以使用str_extract

library(stringr) 
DF$c <- str_extract(DF$a, "\\w(?=_tot)") 
DF$c 
#[1] "c" "d" "g" 
+0

謝謝,這似乎是做的工作! :) – HoHoHo