2015-09-08 78 views
3

我有一個字符串s其中「子字符串」被管道分開。子串可能包含或不包含數字。我有一個測試字符串n,它包含一個數字,可能包含或不包含字母。見下面的例子。請注意,間距可以是任意的R:查找數字是否在字符串範圍內

我試圖刪除所有子字符串,其中n不在一個範圍內或不完全匹配。據我所知,我需要拆分-,轉換爲數字,並比較低/高到n轉換爲數字。這是我的出發點,但後來我陷入了從unl_new中獲得最終好的字符串。

s = "liquid & bar soap 1.0 - 2.0oz | bar 2- 5.0 oz | liquid soap 1-2oz | dish 1.5oz" 
n = "1.5oz" 

unl = unlist(strsplit(s,"\\|")) 

unl_new = (strsplit(unl,"-")) 
unl_new = unlist(gsub("[a-zA-Z]","",unl_new)) 

所需的輸出:

"liquid & bar soap 1.0 - 2.0oz | liquid soap 1-2oz | dish 1.5oz" 

我是完全錯誤的道路上?謝謝!

回答

2

這裏使用R基本的選項;

## extract the n numeric 
nn <- as.numeric(gsub("[^0-9|. ]", "", n)) 
## keep only numeric and -(for interval) 
## and split by | 
## for each interval test the condition to create a boolean vector 
contains_n <- sapply(strsplit(gsub("[^0-9|. |-]", "", s),'[|]')[[1]], 
     function(x){ 
     yy <- strsplit(x, "-")[[1]] 
     yy <- as.numeric(yy[nzchar(yy)]) 
     ## the condition 
     (length(yy)==1 && yy==nn) || length(yy)==2 && nn >= yy[1] && nn <= yy[2] 
     }) 

## split again and use the boolean factor to remove the parts 
## that don't respect the condition 
## paste the result using collapse to get a single character again 
paste(strsplit(s,'[|]')[[1]][contains_n],collapse='') 

## [1] "liquid & bar soap 1.0 - 2.0oz liquid soap 1-2oz dish 1.5oz" 
+1

謝謝!這工作! –

2

不知道這是否是足夠一般,但你可以嘗試:

require(stringr) 
splitted<-strsplit(s,"\\|")[[1]] 
ranges<-lapply(strsplit(
      str_extract(splitted,"[0-9\\.]+(\\s*-\\s*[0-9\\.]+|)"),"\\s*-\\s*"), 
      as.numeric) 
tomatch<-as.numeric(str_extract(n,"[0-9\\.]+")) 
paste(splitted[ 
      vapply(ranges, function(x) (length(x)==1 && x==tomatch) || (length(x)==2 && findInterval(tomatch,x)==1),TRUE)], 
      collapse="|") 
#[1] "liquid & bar soap 1.0 - 2.0oz | liquid soap 1-2oz | dish 1.5oz" 
+1

如果'n = 2.3oz',輸出仍然包括'dish 1.5oz' –

+0

是的,你是對的,我做了一個編輯。 – nicola

+0

謝謝!按預期工作 –

2

下面是從您的unl一步開始的方法使用stringr

unl = unlist(strsplit(s,"\\|")) 
n2 <- as.numeric(gsub("[[:alpha:]]*", "", n)) 
num_lst <- str_extract_all(unl, "\\d\\.?\\d*") 
indx <- lapply(num_lst, function(x) { 
    if(length(x) == 1) {isTRUE(all.equal(n2, as.numeric(x))) 
    } else {n2 >= as.numeric(x[1]) & n2 <= as.numeric(x[2])}}) 

paste(unl[unlist(indx)], collapse=" | ") 
[1] "liquid & bar soap 1.0 - 2.0oz | liquid soap 1-2oz | dish 1.5oz" 

我也與其他款項像"2.3oz"進行了測試。用n2我們強制n爲數字比較。變量num_lst將字符串中的數字隔離開來。

隨着indx我們應用我們的比較字符串數字。如果有一個數字,我們檢查它是否等於n2。我選擇不使用基本的==運營商來避免任何舍入問題。而是使用isTRUE(all.equal(x, y))

最後,使用邏輯索引變量indx對字符串進行子集提取匹配,並用管道"|"將它們粘貼在一起。

+0

'length()'存在哪個包中?無法在'help'中找到它 –

+0

它是R 3.2.0中的一個基本函數 –

+0

它可以用'unlist(lapply(num_lst,length))== 1'代替 –