R:查找数字是否在字符串范围内
R: find if number is within range in a character string
我有一个字符串 s
,其中 "substrings" 被竖线分开。子字符串可能包含也可能不包含数字。我有一个测试字符串 n
,其中包含一个数字,可能包含也可能不包含字母。请参见下面的示例。注意间距可以任意
我正在尝试删除 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"
我是不是完全走错了路?谢谢!
不知道是否够通用,你可以试试:
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"
这里有一个使用 r-base 的选项;
## 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"
这是一个方法,从您的 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
用于对字符串进行子集化以提取匹配项并用管道将它们粘贴在一起"|"
。
我有一个字符串 s
,其中 "substrings" 被竖线分开。子字符串可能包含也可能不包含数字。我有一个测试字符串 n
,其中包含一个数字,可能包含也可能不包含字母。请参见下面的示例。注意间距可以任意
我正在尝试删除 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"
我是不是完全走错了路?谢谢!
不知道是否够通用,你可以试试:
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"
这里有一个使用 r-base 的选项;
## 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"
这是一个方法,从您的 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
用于对字符串进行子集化以提取匹配项并用管道将它们粘贴在一起"|"
。