Сохранять заданные c строковые части при сопоставлении с регулярным выражением - PullRequest
1 голос
/ 24 января 2020

Рассмотрим следующий игрушечный пример:

a <- c(rep(1,3))
b <- c(rep("b", 3))
names <- c("2019 Report", "XYZ Report", "2018 Report")
df <- as.data.frame(cbind(a, b, names))

Я хочу изменить строки в столбце names, но только для имен, которые содержат год:

names_desired <- c("2019 Good Report", "XYZ Report", "2018 Good Report")
df_target <- as.data.frame(cbind(a, b, names, names_desired))

Там Есть много способов сделать это, отфильтровывая имена, не содержащие года, например (упорядочение не имеет значения):

df %>% 
  filter(str_detect(names, "[:digit:]") == FALSE) %>% 
  mutate(names_desired = names) %>% 
  bind_rows(df %>% 
              filter(str_detect(names, "[:digit:]") == TRUE) %>% 
              mutate(names_desired = str_replace(names, "Report", "Good Report")))

Хотя я хочу, чтобы это был способ сопоставления имен с чем-то regex-i sh вот так ( не работает ):

df %>% 
  mutate(names_desired = str_replace(names, "[:digit:]{4} Report", "[:digit:]{4} Good Report"))

В идеале, "[:digit:]{4}" вернул бы цифры, с которыми он совпал, но, конечно, это не так. Есть ли способ сделать это?

1 Ответ

2 голосов
/ 24 января 2020

Один из вариантов - захватить группу ((...)), а затем заменить ее обратными ссылками (\\1, \\2 - в зависимости от порядка захваченных групп)

library(dplyr)
library(stringr)
df <- df %>%
   mutate(names_desired = str_replace(names, '(\\d{4}) (Report)', '\\1 Good \\2'))
df
#    a b       names    names_desired
#1 1 b 2019 Report 2019 Good Report
#2 1 b  XYZ Report       XYZ Report
#3 1 b 2018 Report 2018 Good Report

В этом В этом случае «Отчет» исправлен, поэтому нам нужно захватить только одну группу

df %>%
   mutate(names_desired = str_replace(names, '(\\d{4}) Report', '\\1 Good Report'))

или с использованием base R

sub("(\\d{4}) (Report)", "\\1 Good \\2", df$names)
#[1] "2019 Good Report" "XYZ Report"       "2018 Good Report"

data

df <- data.frame(a, b, names)
...