6

I have some html code I'm working with. I want to extract certain strings.

I want to extract this from string x preferred using base R: coleman_l, SMOG4

Here is what I have:

x <- "<code>(hi)<a href=\"Read\">auto</a></code>(coleman_l, SMOG4)<br />Read</li>" 
#remove the string (this works)
gsub("a></code>(.+?)<br", "a></code><br", x)

#> gsub("a></code>(.+?)<br", "a></code><br", x)
#[1] "<code>(hi)<a href=\"Read\">auto</a></code><br />Read</li>"

#attempt to extract that information (doesn't work)
re <- "(?<=a></code>().*?(?=)<br)"
regmatches(x, gregexpr(re, x, perl=TRUE))

Error message:

> regmatches(x, gregexpr(re, x, perl=TRUE)) 
Error in gregexpr(re, x, perl = TRUE) : 
  invalid regular expression '(?<=a></code>().*?(?=)<br)'
In addition: Warning message:
In gregexpr(re, x, perl = TRUE) : PCRE pattern compilation error
        'lookbehind assertion is not fixed length'
        at ')'

    enter code here

NOTE: Tagged as regex but this is R specific regex.

Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519

3 Answers3

8

For these types of problems, I would use backreferences to extract the portion I want.

x <- 
  "<code>(hi)<a href=\"Read\">auto</a></code>(coleman_l, SMOG4)<br />Read</li>" 
gsub(".*a></code>(.+?)<br.*", "\\1", x)
# [1] "(coleman_l, SMOG4)"

If the parentheses should also be removed, add them to the "plain text" part that you are tying to match, but remember that they would need to be escaped:

gsub(".*a></code>\\((.+?)\\)<br.*", "\\1", x)
# [1] "coleman_l, SMOG4"
A5C1D2H2I1M1N2O1R2T1
  • 190,393
  • 28
  • 405
  • 485
7

FWIW, OP's original approach could have worked with little tweak.

> x
[1] "<code>(hi)<a href=\"Read\">auto</a></code>(coleman_l, SMOG4)<br />Read</li>"
> re <- "(?<=a></code>\\().*?(?=\\)<br)"
> regmatches(x, gregexpr(re, x, perl=TRUE))
[[1]]
[1] "coleman_l, SMOG4"

An advantage of doing it this way compared to other suggested solution is that if there is possibility of multiple matches, then all of them will show up.

> x <- '<code>(hi)<a href=\"Read\">auto</a></code>(coleman_l, SMOG4)<br />Read</li><code>(hi)<a href=\"Read\">auto</a></code>(coleman_l_2, SMOG4_2)<br />Read</li>'
> regmatches(x, gregexpr(re, x, perl=TRUE))
[[1]]
[1] "coleman_l, SMOG4"     "coleman_l_2, SMOG4_2"
CHP
  • 16,981
  • 4
  • 38
  • 57
5

This will work, despite being ugly.

x<-"<code>(hi)<a href=\"Read\">auto</a></code>(coleman_l, SMOG4)<br />Read</li>"

x2 <- gsub("^.+(\\(.+\\)).+\\((.+)\\).+$","\\2",x)
x2
[1] "coleman_l, SMOG4"
thelatemail
  • 91,185
  • 12
  • 128
  • 188