Replace values using grepl in r with substrings

Viewed 305

Following data.table

df <- data.table(id=c(1,2,3,4,5),
                 variable=c("250.00","250.13","250.56","250.01","Value1"))
1:  1   250.00
2:  2   250.13
3:  3   250.56
4:  4   250.01
5:  5   Value1

I want to replace every of the 250. numbers that end with an odd number with Value1 and the others that end with an even number with Value2. I tried to use the grepl function in the following way.

df$variable[grepl('250\\.[0-9]1|3|5', df$variable)] <-'Value1'
df$variable[grepl('250\\.[0-9]0|2|4', df$variable)] <-'Value2'

But it replaces all the 250. with Value1. How is the best way to get these results:

1:  1   Value2
2:  2   Value1
3:  3   Value2
4:  4   Value1
5:  5   Value1

In the original data.table there are more values. A solution with base that can deal with data.table would be great.

3 Answers

The reason for this is your regex expression. This is an app that is really helpful in understanding what your regex will match. https://spannbaueradam.shinyapps.io/r_regex_tester/

250\\.[0-9]1|3|5 is searching for 250\\.[0-9]1 OR 3 OR 5 and since all 250.x contain 5, they're all a match.

250\\.[0-9][135] will look a value that ends with 1, 3, or 5***. Values in [] are considered an OR list.

*** this isn't 100% correct, that pattern would be [135]$, but that would match 'Value1' because it ends in a 1.

Another way you can do using stringr library

library(dplyr)
library(stringr)
df %>% 
  mutate(variable = str_replace_all(variable, c("250.\\d?[13579]$" = "Value1", "250.\\d?[02468]$" = "Value2")))
#     id variable
# 1:  1   Value2
# 2:  2   Value1
# 3:  3   Value2
# 4:  4   Value1
# 5:  5   Value1

We could also use

library(data.table)
df[grepl('^[0-9]', variable),  variable := 
     c("Value2", "Value1")[(as.integer(sub(".*\\.", "", variable)) %% 2)+1]]
df
#   id variable
#1:  1   Value2
#2:  2   Value1
#3:  3   Value2
#4:  4   Value1
#5:  5   Value1
Related