Str_replace A1-A9 - A01-A09 и т.д.
Привет У меня есть следующие строки в моих данных и я хотел бы заменить 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
Здесь есть аналогичный пост , но моя проблема немного отличается! и не видели подобного примера здесь str_replace.
Будет очень рад, если вы знаете решение.
ожидаемый выход
Str
1 A01B10
2 A02B03
3 A11B01
4 A05B10
Ответы
Ответ 1
Я думаю, что это должно получить то, что вы хотите:
gsub("(?<![0-9])([0-9])(?![0-9])", "0\\1", rep_data$Str, perl = TRUE)
#[1] "A01B10" "A02B03" "A11B01" "A05B10"
Он использует поиск /lookbehind PCRE для соответствия 1-значному числу, а затем вставляет на него "0".
Ответ 2
Как насчет чего-то вроде этого
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()
для нулевого заполнения их до двух символов. Затем вставляем добавленные значения в вектор и вставляем все обратно.
Ответ 3
Не проверено полностью
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"
Ответ 4
Решение от 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
Ответ 5
Это самое сжатое решение, которое я могу придумать:
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)
Ответ 6
Вот один из вариантов: gsubfn
library(gsubfn)
gsubfn("(\\d+)", ~sprintf("%02d", as.numeric(x)), as.character(rep_data$Str))
#[1] "A01B10" "A02B03" "A11B01" "A05B10"
Ответ 7
Немного похоже на ответ @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-й группе захвата. Вместо этого он заменяет совпадение первой группой захвата плюс нуль сразу после.