通过 gsub / regex 从混乱的向量中选择数字
Selecting digits from messy vector via gsub / regex
我正在使用一个向量 vecA 对应于下面生成的向量:
vecA <- c("[ 0, 10)", "[ 10, 20)", "[ 20, 30)", "[ 50, 60)", "[ 90,100]")
我想达到 vecB 删除特殊字符并插入连字符的目的,如以下生成的示例所示:
vecB <- c("0 - 10", "10 - 20", "20 - 30", "50 - 60", "90 - 100")
问题
我有 gsub
语法,几乎 有效:
vecB <- gsub(pattern =
"^(\[{1})([[:blank:]]*)(\d{1,2})([,])(.*)(\d{2,3})([[:punct:]])$",
x = vecA, replacement = "\3 - \6")
唯一的问题是值 [ 90,100]
被错误地转换为 90 - 00
而不是 90 - 100
应该是 (regex101).
我们可以使用捕获组,即在 (..)
中获取数字部分并删除所有其他部分,即非数字 (\D+
)。
在下面的模式中,我们匹配一个或多个非数字元素(\D+
- 它包括 [
和它后面的白色 space),然后捕获一个或更多数字((\d+)
),然后匹配一个或多个非数字(\D+
-匹配,
和白色space),第二个捕获数字组(\d+
) 后跟 .*
即它匹配字符串的其余部分直到它的末尾。在替换中,我们指定反向引用 (\1
) 后跟 space 然后是 -
和第二个反向引用 ('\2`).
sub('\D+(\d+)\D+(\d+).*', '\1 - \2', vecA)
#[1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
编辑:基于@Wiktor Stribiżew 的评论
或者我们可以使用 library(stringr)
中的 str_extract
来提取数字,然后 paste
一起
library(stringr)
sapply(str_extract_all(vecA, '[0-9]+'), paste, collapse=' - ')
#[1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
1) sub/gsub 这可以分成两个简单的 sub/gsub 调用。内部 gsub
将任何不是数字或逗号的内容替换为空字符串,外部 sub
将逗号转换为 space-minus-space.
sub(",", " - ", gsub("[^0-9,]", "", vecA))
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
2) 一个子 用一个sub
:
sub("^\D*(\d+)\D*(\d+)\D*$", "\1 - \2", vecA)
## "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
3) substring/read.table 这个不使用 sub 或 gsub 或任何正则表达式:
with(read.table(text = substring(vecA, 2, nchar(vecA)-1), sep = ","), paste(V1, "-", V2))
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
3a) (3) 的变体略短:
with(read.table(text = gsub("\D", " ", vecA)), paste(V1, "-", V2))
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
4) gsubfn 这会提取捕获组并执行指定的 paste
:
library(gsubfn)
strapply(vecA, "(\d+)\D*(\d+)", ~ paste(x, "-", y), simplify = c)
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
4a) (4) 的变体,使用 stapplyc
而不是 strapply
:
library(gsubfn)
sapply(strapplyc(vecA, "\d+"), paste, collapse = " - ")
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
4b) (4) 的变体,使用 gsubfn 而不是 strapply
:
library(gsubfn)
gsubfn("\D+", ~ if (grepl(",", x)) " - " else "", vecA)
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
5) strsplit 这是另一种不使用sub或gsub的解决方案:
f <- function(x) {
paste0(ifelse(x == ",", " - ", ifelse(x %in% 0:9, x, "")), collapse = "")
}
sapply(strsplit(vecA, ""), f)
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
提醒我,我正在很好地解决标记间隔的相同问题。这是我的结果,忽略其中没有正则表达式:
library(dplyr)
# 1-9 by one, up to 75 by 5, up to 300 by 50, rest by 100
c(0:9,
seq(14, 50, by=5),
seq(59, 100, by=10),
seq(149, 300, by=50),
seq(400, 1000, by=100)) ->
breaks
# create nice labels for the intervals
# assuming integral numbers will be cut by the breaks (hence the `l + 1`)
data.frame(l = breaks[1:length(breaks) - 1],
r = breaks[2:length(breaks)]) %>%
mutate(diff = r - l,
lab = ifelse(diff > 1,
paste0(l + 1, " - ", r),
as.character(r))) ->
labs
# and cut() the data in `pos` colum getting directly the factors with
# nice names
d %>% mutate(bin=cut(pos, breaks, labels=labs$lab))
我正在使用一个向量 vecA 对应于下面生成的向量:
vecA <- c("[ 0, 10)", "[ 10, 20)", "[ 20, 30)", "[ 50, 60)", "[ 90,100]")
我想达到 vecB 删除特殊字符并插入连字符的目的,如以下生成的示例所示:
vecB <- c("0 - 10", "10 - 20", "20 - 30", "50 - 60", "90 - 100")
问题
我有 gsub
语法,几乎 有效:
vecB <- gsub(pattern =
"^(\[{1})([[:blank:]]*)(\d{1,2})([,])(.*)(\d{2,3})([[:punct:]])$",
x = vecA, replacement = "\3 - \6")
唯一的问题是值 [ 90,100]
被错误地转换为 90 - 00
而不是 90 - 100
应该是 (regex101).
我们可以使用捕获组,即在 (..)
中获取数字部分并删除所有其他部分,即非数字 (\D+
)。
在下面的模式中,我们匹配一个或多个非数字元素(\D+
- 它包括 [
和它后面的白色 space),然后捕获一个或更多数字((\d+)
),然后匹配一个或多个非数字(\D+
-匹配,
和白色space),第二个捕获数字组(\d+
) 后跟 .*
即它匹配字符串的其余部分直到它的末尾。在替换中,我们指定反向引用 (\1
) 后跟 space 然后是 -
和第二个反向引用 ('\2`).
sub('\D+(\d+)\D+(\d+).*', '\1 - \2', vecA)
#[1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
编辑:基于@Wiktor Stribiżew 的评论
或者我们可以使用 library(stringr)
中的 str_extract
来提取数字,然后 paste
一起
library(stringr)
sapply(str_extract_all(vecA, '[0-9]+'), paste, collapse=' - ')
#[1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
1) sub/gsub 这可以分成两个简单的 sub/gsub 调用。内部 gsub
将任何不是数字或逗号的内容替换为空字符串,外部 sub
将逗号转换为 space-minus-space.
sub(",", " - ", gsub("[^0-9,]", "", vecA))
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
2) 一个子 用一个sub
:
sub("^\D*(\d+)\D*(\d+)\D*$", "\1 - \2", vecA)
## "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
3) substring/read.table 这个不使用 sub 或 gsub 或任何正则表达式:
with(read.table(text = substring(vecA, 2, nchar(vecA)-1), sep = ","), paste(V1, "-", V2))
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
3a) (3) 的变体略短:
with(read.table(text = gsub("\D", " ", vecA)), paste(V1, "-", V2))
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
4) gsubfn 这会提取捕获组并执行指定的 paste
:
library(gsubfn)
strapply(vecA, "(\d+)\D*(\d+)", ~ paste(x, "-", y), simplify = c)
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
4a) (4) 的变体,使用 stapplyc
而不是 strapply
:
library(gsubfn)
sapply(strapplyc(vecA, "\d+"), paste, collapse = " - ")
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
4b) (4) 的变体,使用 gsubfn 而不是 strapply
:
library(gsubfn)
gsubfn("\D+", ~ if (grepl(",", x)) " - " else "", vecA)
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
5) strsplit 这是另一种不使用sub或gsub的解决方案:
f <- function(x) {
paste0(ifelse(x == ",", " - ", ifelse(x %in% 0:9, x, "")), collapse = "")
}
sapply(strsplit(vecA, ""), f)
## [1] "0 - 10" "10 - 20" "20 - 30" "50 - 60" "90 - 100"
提醒我,我正在很好地解决标记间隔的相同问题。这是我的结果,忽略其中没有正则表达式:
library(dplyr)
# 1-9 by one, up to 75 by 5, up to 300 by 50, rest by 100
c(0:9,
seq(14, 50, by=5),
seq(59, 100, by=10),
seq(149, 300, by=50),
seq(400, 1000, by=100)) ->
breaks
# create nice labels for the intervals
# assuming integral numbers will be cut by the breaks (hence the `l + 1`)
data.frame(l = breaks[1:length(breaks) - 1],
r = breaks[2:length(breaks)]) %>%
mutate(diff = r - l,
lab = ifelse(diff > 1,
paste0(l + 1, " - ", r),
as.character(r))) ->
labs
# and cut() the data in `pos` colum getting directly the factors with
# nice names
d %>% mutate(bin=cut(pos, breaks, labels=labs$lab))