R Regex: modifying digits of varying lengths at end of string

Viewed 54

I'm trying to use regex to add decimals to any numbers following dollar signs within a vector of strings. I've been partially successful thus far but am having trouble with instances that occur at the end of string. Here's an example of the issue:

ex <- tibble(strings = c("10/$20/$30", "$40/50/60", "$70.00/80/$90.00"))

gsub("(\\$[0-9]+)([^\\.])", "\\1\\.00\\2", ex$strings)

Which I believe to mean, to identify sub-strings which begin with a dollar sign and at least one digit but not followed by a period and replace them with the dollar sign and current digit(s) followed by a decimal and two zeroes... but which yields:

[1] "10/$20.00/$3.000"       "$40.00/50/60"           "$7.000.00/80/$9.000.00" 

I see that it's returning the desired result for all dollar values not located at the end of a string but, as evidenced by the first and third string, it's clear that I'm still missing an ingredient.

It seems as though I have two problems, the first is matching strings that fall at the end of a string ($30) and the other is dollar values that already have decimals.

2 Answers

The following logic seems to work:

x <- c("10/$20/$30", "$40/50/60", "$70.00/80/$90.00")
gsub("(\\$\\d+)(?![^/])", "\\1.00", x, perl=TRUE)

[1] "10/$20.00/$30.00" "$40.00/50/60"     "$70.00/80/$90.00"

Here is an explanation of the regex pattern:

(\\$\\d+)  match and capture '$' followed by one or more digits
(?![^/])   which is also followed by either '/' or the end of the input

Then we replace with the captured quantity followed by .00. Note that the negative lookahead (?![^/]) excludes inputs which already have a decimal component.

Just to try it with a 3 digit number I modified your ex a bit

    ex <- tibble(strings = c("10/$20/$30", "$40/50/60", "$70.00/80/$90.00/$100"))

Then I used stringr::str_replace_all

str_replace_all(ex$strings,"(?<=\\$)(\\d+)\\b(?!\\.00)","\\1\\.00")

This was a bit trickier then I intended it to be because of the issue of using a literal $ in the replacement string. It's discussed here https://github.com/tidyverse/stringr/issues/83 but I'm not sure if/what the resolution was.

So I made the string that needs to be replaced the following: one or more digits which follows a $ and terminates a "word" but does not precede .00. The last part prevents matching of instances such as $70.00

I then replace those digits with those digits (signified by the first capturing group or \\1) plus .00

My results are:

"10/$20.00/$30.00"  "$40.00/50/60"  "$70.00/80/$90.00/$100.00"
Related