str_replace A1-A9 至 A01-A09 依此类推
str_replace A1-A9 to A01-A09 and so on
您好,我的数据中有以下字符串,我想将 A1-A9 替换为 A01-A09,将 B1-B9 替换为 B01-B09,但保留数字 >=10
。
rep_data=data.frame(Str= c("A1B10", "A2B3", "A11B1", "A5B10"))
Str
1 A1B10
2 A2B3
3 A11B1
4 A5B10
有一个类似的post but my problem is little bit different! and haven't seen similar example in here str_replace.
如果您知道解决方案,将非常高兴。
预期输出
Str
1 A01B10
2 A02B03
3 A11B01
4 A05B10
这样的怎么样
num_pad <- function(x) {
x <- as.character(x)
mm <- gregexpr("\d+|\D+",x)
parts <- regmatches(x, mm)
pad_number <- function(x) {
nn<-suppressWarnings(as.numeric(x))
x[!is.na(nn)] <- sprintf("%02d", nn[!is.na(nn)])
x
}
parts <- lapply(parts, pad_number)
sapply(parts, paste0, collapse="")
}
num_pad(rep_data$Str)
# [1] "A01B10" "A02B03" "A11B01" "A05B10"
基本上我们使用正则表达式将字符串分成数字组和非数字组。然后我们找到那些看起来像数字的值,并使用 sprintf()
将它们零填充为 2 个字符。然后我们将填充值插入到向量中并将所有内容粘贴回一起。
我认为这应该能满足您的需求:
gsub("(?<![0-9])([0-9])(?![0-9])", "0\1", rep_data$Str, perl = TRUE)
#[1] "A01B10" "A02B03" "A11B01" "A05B10"
它使用 PCRE lookahead's/lookbehind' 来匹配一位数字,然后将“0”粘贴到它上面。
没有仔细检查
x = c("A1B10", "A2B3", "A11B1", "A5B10")
sapply(strsplit(x, ""), function(s){
paste(sapply(split(s, cumsum(s %in% LETTERS)), function(a){
if(length(a) == 2){
a[2] = paste0(0, a[2])
}
paste(a, collapse = "")
}), collapse = "")
})
#[1] "A01B10" "A02B03" "A11B01" "A05B10"
来自 tidyverse
和 stringr
的解决方案。
library(tidyverse)
library(stringr)
rep_data2 <- rep_data %>%
extract(Str, into = c("L1", "N1", "L2", "N2"), regex = "(A)(\d+)(B)(\d+)") %>%
mutate_at(vars(starts_with("N")), funs(str_pad(., width = 2, pad = "0"))) %>%
unite(Str, everything(), sep = "")
rep_data2
Str
1 A01B10
2 A02B03
3 A11B01
4 A05B10
这是我能想到的最简洁整洁的解决方案:
library(tidyverse)
library(stringr)
rep_data %>%
mutate(
num_1 = str_match(Str, "A([0-9]+)")[, 2],
num_2 = str_match(Str, "B([0-9]+)")[, 2],
num_1 = str_pad(num_1, width = 2, side = "left", pad = "0"),
num_2 = str_pad(num_2, width = 2, side = "left", pad = "0"),
Str = str_c("A", num_1, "B", num_2)
) %>%
select(- num_1, - num_2)
这里有一个选项gsubfn
library(gsubfn)
gsubfn("(\d+)", ~sprintf("%02d", as.numeric(x)), as.character(rep_data$Str))
#[1] "A01B10" "A02B03" "A11B01" "A05B10"
有点类似于@Mike 的回答,但是这个解决方案使用了一个积极的前瞻:
gsub("(\D)(?=\d(\D|\b))", "\10", rep_data$Str, perl = TRUE)
# [1] "A01B10" "A02B03" "A11B01" "A05B10"
与tidyverse
:
library(dplyr)
library(stringr)
rep_data %>%
mutate(Str = str_replace_all(Str, "(\D)(?=\d(\D|\b))", "\10"))
# Str
# 1 A01B10
# 2 A02B03
# 3 A11B01
# 4 A05B10
此正则表达式匹配所有后跟数字和另一个非数字或单词边界的非数字。 \10
非常具有欺骗性,因为它看起来像是用第 10 个捕获组替换匹配项。相反,它将匹配替换为第一个捕获组加上一个零。
您好,我的数据中有以下字符串,我想将 A1-A9 替换为 A01-A09,将 B1-B9 替换为 B01-B09,但保留数字 >=10
。
rep_data=data.frame(Str= c("A1B10", "A2B3", "A11B1", "A5B10"))
Str
1 A1B10
2 A2B3
3 A11B1
4 A5B10
有一个类似的post
如果您知道解决方案,将非常高兴。
预期输出
Str
1 A01B10
2 A02B03
3 A11B01
4 A05B10
这样的怎么样
num_pad <- function(x) {
x <- as.character(x)
mm <- gregexpr("\d+|\D+",x)
parts <- regmatches(x, mm)
pad_number <- function(x) {
nn<-suppressWarnings(as.numeric(x))
x[!is.na(nn)] <- sprintf("%02d", nn[!is.na(nn)])
x
}
parts <- lapply(parts, pad_number)
sapply(parts, paste0, collapse="")
}
num_pad(rep_data$Str)
# [1] "A01B10" "A02B03" "A11B01" "A05B10"
基本上我们使用正则表达式将字符串分成数字组和非数字组。然后我们找到那些看起来像数字的值,并使用 sprintf()
将它们零填充为 2 个字符。然后我们将填充值插入到向量中并将所有内容粘贴回一起。
我认为这应该能满足您的需求:
gsub("(?<![0-9])([0-9])(?![0-9])", "0\1", rep_data$Str, perl = TRUE)
#[1] "A01B10" "A02B03" "A11B01" "A05B10"
它使用 PCRE lookahead's/lookbehind' 来匹配一位数字,然后将“0”粘贴到它上面。
没有仔细检查
x = c("A1B10", "A2B3", "A11B1", "A5B10")
sapply(strsplit(x, ""), function(s){
paste(sapply(split(s, cumsum(s %in% LETTERS)), function(a){
if(length(a) == 2){
a[2] = paste0(0, a[2])
}
paste(a, collapse = "")
}), collapse = "")
})
#[1] "A01B10" "A02B03" "A11B01" "A05B10"
来自 tidyverse
和 stringr
的解决方案。
library(tidyverse)
library(stringr)
rep_data2 <- rep_data %>%
extract(Str, into = c("L1", "N1", "L2", "N2"), regex = "(A)(\d+)(B)(\d+)") %>%
mutate_at(vars(starts_with("N")), funs(str_pad(., width = 2, pad = "0"))) %>%
unite(Str, everything(), sep = "")
rep_data2
Str
1 A01B10
2 A02B03
3 A11B01
4 A05B10
这是我能想到的最简洁整洁的解决方案:
library(tidyverse)
library(stringr)
rep_data %>%
mutate(
num_1 = str_match(Str, "A([0-9]+)")[, 2],
num_2 = str_match(Str, "B([0-9]+)")[, 2],
num_1 = str_pad(num_1, width = 2, side = "left", pad = "0"),
num_2 = str_pad(num_2, width = 2, side = "left", pad = "0"),
Str = str_c("A", num_1, "B", num_2)
) %>%
select(- num_1, - num_2)
这里有一个选项gsubfn
library(gsubfn)
gsubfn("(\d+)", ~sprintf("%02d", as.numeric(x)), as.character(rep_data$Str))
#[1] "A01B10" "A02B03" "A11B01" "A05B10"
有点类似于@Mike 的回答,但是这个解决方案使用了一个积极的前瞻:
gsub("(\D)(?=\d(\D|\b))", "\10", rep_data$Str, perl = TRUE)
# [1] "A01B10" "A02B03" "A11B01" "A05B10"
与tidyverse
:
library(dplyr)
library(stringr)
rep_data %>%
mutate(Str = str_replace_all(Str, "(\D)(?=\d(\D|\b))", "\10"))
# Str
# 1 A01B10
# 2 A02B03
# 3 A11B01
# 4 A05B10
此正则表达式匹配所有后跟数字和另一个非数字或单词边界的非数字。 \10
非常具有欺骗性,因为它看起来像是用第 10 个捕获组替换匹配项。相反,它将匹配替换为第一个捕获组加上一个零。