Extracting all numbers in a string that are surrounded by a certain pattern in R

Viewed 322

I'd like to extract all numbers in a string that are flanked by two markers/patterns. However, regular expressions in R are my bane.

I have something like this:

string  <- "<img src='images/stimuli/32.png' style='width:341.38790035587186px;height: 265px;'><img src='images/stimuli/36.png' style='width:341.38790035587186px;height: 265px;'>"
marker1 <- "images/stimuli/"
marker2 <- ".png"

and want something like this

gsub(paste0(".*", marker1, "*(.*?) *", marker2, ".*"), "\\1", string)

[1] "32" "36"

However I get this:

[1] "32"

PS If someone has a good guide to understand how regular expressions work here, please let me know. I am pretty sure that the answer is pretty simple but I just don't get regex :(

2 Answers

You may use

string  <- "<img src='images/stimuli/32.png' style='width:341.38790035587186px;height: 265px;'><img src='images/stimuli/36.png' style='width:341.38790035587186px;height: 265px;'>"
regmatches(string, gregexpr("images/stimuli/\\K\\d+(?=\\.png)", string, perl=TRUE))[[1]]
# => [1] "32" "36"

NOTE: If there can be anything, not just numbers, you may replace \\d+ with .*?.

See the R demo and a regex demo.

The regmatches with gregexpr extract all matches found in the input.

The regex matches:

  • images/stimuli/ - a literal string
  • \K - a match reset operator discarding all text matched so far
  • \d+ - 1+ digits
  • (?=\.png) - a .png substring (. is a special character, it needs escaping).

You can use str_extract from the package stringr:

library(stringr)
str_extract_all(string, "(?<=images/stimuli/)\\d+(?=\\.png)")
[[1]]
[1] "32" "36"

This solution uses positive lookbehind, (?<=images/stimuli/), and positive lookahead, (?=\\.png), which are both non-capturing groups, and instead matches one or more numbers, \\d+, sitting between the two.

Related