Search code examples
rregexvalidationparsingescaping

R: How to make parse() accept regular expressions with escaped characters?


I am trying to use the validator package to check if certain rows in my data table contain a regular expression or not.

I make a vector (fields) with the columns I want to test and then paste together the commands for the validator rules as a string.

To be able to use the rules in the confront() function I use parse() and eval() to turn the character string into an expression

The following example is working as expected:

library(validate)

  data <- data.frame("Protocol_Number" = c("123", "A122"), "Numeric_Result" = c("-0.5", "1.44"))
  fields <- c("Protocol_Number", "Numeric_Result")
  
  # build validator commands for each field
  cmds <- paste("validator(",
                paste(
                  map_chr(
                    fields, function(x) paste0("grepl('^-?[0-9]', as.character(`", x, "`))")
                  ), collapse = ","),
                ")")
  
  # convert to rule and do the tests
  rule <- eval(parse(text = cmds))
  out <- confront(data, rule)
  summary(out)

However, I want to use a regex that recognizes any sort of number as opposed to text, like in this working example

grepl('^-?[0-9]\\d*(\\.\\d+)?$', c(1, -1, 0.5, "Not Done"))

When I try to use this regex in the above example, the parse() function will throw an error:

Error: '\d' is an unrecognized escape in character string starting "'^-?[0-9]\d"

This is not working:

  
  # build validator commands for each field
  cmds <- paste("validator(",
                paste(
                  map_chr(
                    fields, function(x) paste0("grepl('^-?[0-9]\\d*(\\.\\d+)?$', as.character(`", x, "`))")
                  ), collapse = ","),
                ")")
  
  # convert to rule and do the tests
  rule <- eval(parse(text = cmds))
  out <- confront(data, rule)
  summary(out)

How do I make parse() accept the escaped characters? Or is there a better way to do this?


Solution

  • We may escape it with \\

    cmds <- paste("validator(",
                     paste(
                       map_chr(
                         fields, function(x) 
       paste0("grepl('^-?[0-9]\\\\d*(\\\\.\\\\d+)?$', as.character(`", x, "`))")
                       ), collapse = ","),
                     ")")
    

    -testing

    > rule <- eval(parse(text = cmds))
    > 
    >  out <- confront(data, rule)
    > out
    Object of class 'validation'
    Call:
        confront(dat = data, x = rule)
    
    Rules confronted: 2
       With fails   : 1
       With missings: 0
       Threw warning: 0
       Threw error  : 0