2015-09-08 3 views
3

У меня есть строка s, где «подстроки» делятся на трубу. Подстроки могут содержать или не содержать числа. И у меня есть тестовая строка символов n, которая содержит число и может содержать или не содержать буквы. См. Пример ниже. Обратите внимание, что расстояние может быть любымR: найдите, если номер находится в пределах диапазона в символьной строке

Я пытаюсь сбросить все подстроки, где n не находится в диапазоне или не является точным соответствием. Я понимаю, что мне нужно разделить на -, преобразовать в числа и сравнить low/high с 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

Здесь вариант с использованием г-базы;

## 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

if '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

В каком пакете существует 'lengths()' существует? Невозможно найти его в 'help' –

+0

Это базовая функция в R 3.2.0 –

+0

Его можно заменить на' unlist (lapply (num_lst, length)) == 1' –

 Смежные вопросы

  • Нет связанных вопросов^_^