R Use Regular Expression to capture number when sometimes the capture is at the end of the string or not

Viewed 73

I need to capture the numbers out of a string that come after a certain parameter name.

I have it working for most, but there is one parameter that is sometimes at the end of the string, but not always. When using the regular expression, it seems to matter.

I've tried different things, but nothing seems to work in both cases.

# Regular expression to capture the digit after the phrase "AppliedWhenID="
p <- ".*&AppliedWhenID=(.\\d*)"

# Tried this, but when at end, it just grabs a blank
#p <- ".*&AppliedWhenID=(.\\d*)&.*|.*&AppliedWhenID=(.\\d*)$"

testAtEnd <- "ReportType=233&ReportConID=171&MonthQuarterYear=0TimePeriodLabel=Year%202020&AppliedWhenID=2"

testNotAtEnd <- "ReportType=233&ReportConID=171&MonthQuarterYear=0TimePeriodLabel=Year%202020&AppliedWhenID=2&AgDateTypeID=1"


# What should be returned is "2"

gsub(p, "\\1", testAtEnd) # works
gsub(p, "\\1", testNotAtEnd) # doesn't work, it captures 2 + &AgDateTypeID=1
2 Answers

Note that sub and gsub replace the found text(s), thus, in order to extract a part of the input string with a capturing group + a backreference, you need to actually match (and consume) the whole string.

Hence, you need to match the string to the end by adding .* at the end of the pattern:

p <- ".*&AppliedWhenID=(\\d+).*"
sub(p, "\\1", testNotAtEnd)
# => [1] "2"
sub(p, "\\1", testAtEnd)
# => [1] "2"

See the regex demo and the R online demo.

Note that gsub matches multiple occurrences, you need a single one, so it makes sense to replace gsub with sub.

Regex details

  • .* - any zero or more chars as many as possible
  • &AppliedWhenID= - a &AppliedWhenID= string
  • (\d+) - Group 1 (\1): one or more digits
  • .* - any zero or more chars as many as possible.

You could try using the string look behind conditional "(?<=)" and str_extract() from the stringr library.

testAtEnd <- "ReportType=233&ReportConID=171&MonthQuarterYear=0TimePeriodLabel=Year%202020&AppliedWhenID=2"

testNotAtEnd <- "ReportType=233&ReportConID=171&MonthQuarterYear=0TimePeriodLabel=Year%202020&AppliedWhenID=2&AgDateTypeID=1"

p <- "(?<=AppliedWhenID=)\\d+"

# What should be returned is "2"
library(stringr)
str_extract(testAtEnd, p)
str_extract(testNotAtEnd, p)

Or in base R

p <- ".*((?<=AppliedWhenID=)\\d+).*"

gsub(p, "\\1", testAtEnd, perl=TRUE) 
gsub(p, "\\1", testNotAtEnd, perl=TRUE) 
Related