2017-10-24 22 views
10

Xin chào Tôi có một chuỗi sau trong dữ liệu của tôi và muốn thay thế A1-A9 thành A01-A09 và B1-B9 thành B01-B09 nhưng giữ số >=10.str_replace A1-A9 đến A01-A09 và cứ thế

rep_data=data.frame(Str= c("A1B10", "A2B3", "A11B1", "A5B10")) 

    Str 
1 A1B10 
2 A2B3 
3 A11B1 
4 A5B10 

Có bài viết tương tự here nhưng vấn đề của tôi hơi khác một chút! và chưa thấy ví dụ tương tự ở đây str_replace.

Sẽ rất vui nếu bạn biết giải pháp.

sản lượng dự kiến ​​

Str 
1 A01B10 
2 A02B03 
3 A11B01 
4 A05B10 
+0

Đó có phải là yêu cầu quan trọng để sử dụng * gọn gàng * không? –

+0

không nhất thiết! – Alexander

Trả lời

6

Tôi nghĩ rằng điều này sẽ giúp bạn có được những gì bạn muốn:

gsub("(?<![0-9])([0-9])(?![0-9])", "0\\1", rep_data$Str, perl = TRUE) 
#[1] "A01B10" "A02B03" "A11B01" "A05B10" 

Nó sử dụng PCRE lookahead của/lookbehind để phù hợp với một số 1 chữ số và sau đó dán một "0" vào nó.

+0

giữa ([0-9]) là gì? – Alexander

+1

Nó khớp với một chữ số. Các từ xung quanh giữa '([0-9])' khớp với các chữ số không –

3

Làm thế nào về một cái gì đó như thế này

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" 

Về cơ bản chúng tôi sử dụng biểu thức thông thường để phân chia các chuỗi lên thành các nhóm chữ số và phi số. Sau đó, chúng tôi tìm thấy các giá trị đó giống như số và sử dụng sprintf() để không đặt chúng vào 2 ký tự. Sau đó, chúng tôi chèn các giá trị đệm vào vectơ và dán mọi thứ lại với nhau.

2

Không kiểm tra kỹ lưỡng

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" 
2

Một giải pháp từ tidyversestringr.

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 
2

Đây là giải pháp gọn gàng súc tích nhất mà tôi có thể đưa ra:

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) 
1

Đây là một lựa chọn với gsubfn

library(gsubfn) 
gsubfn("(\\d+)", ~sprintf("%02d", as.numeric(x)), as.character(rep_data$Str)) 
#[1] "A01B10" "A02B03" "A11B01" "A05B10" 
1

Một chút tương tự như @ câu trả lời của Mike, nhưng điều này giải pháp sử dụng một lookahead tích cực:

gsub("(\\D)(?=\\d(\\D|\\b))", "\\10", rep_data$Str, perl = TRUE) 
# [1] "A01B10" "A02B03" "A11B01" "A05B10" 

Với 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 

regex này phù hợp với tất cả các phi chữ số được theo sau là một chữ số và bằng cách khác không chữ số hoặc một ranh giới từ. \\10 khá lừa dối vì có vẻ như nó đang thay thế trận đấu với nhóm chụp thứ 10. Thay vào đó, nó thay thế kết quả phù hợp với nhóm chụp thứ nhất cộng với số 0 ngay sau đó.

Các vấn đề liên quan