Pegah
Pegah

Reputation: 23

Replace a specific character only between parenthesis

Lest's say I have a string:

test <- "(pop+corn)-bread+salt"

I want to replace the plus sign that is only between parenthesis by '|', so I get:

"(pop|corn)-bread+salt"

I tried:

gsub("([+])","\\|",test)

But it replaces all the plus signs of the string (obviously)

Upvotes: 1

Views: 766

Answers (2)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626689

If you want to replace all + symbols that are inside parentheses (if there may be 1 or more), you can use any of the following solutions:

gsub("\\+(?=[^()]*\\))", "|", x, perl=TRUE)

See the regex demo. Here, the + is only matched when it is followed with any 0+ chars other than ( and ) (with [^()]*) and then a ). It is only good if the input is well-formed and there is no nested parentheses as it does not check if there was a starting (.

gsub("(?:\\G(?!^)|\\()[^()]*?\\K\\+", "|", x, perl=TRUE)

This is a safer solution since it starts matching + only if there was a starting (. See the regex demo. In this pattern, (?:\G(?!^)|\() matches the end of the previous match (\G(?!^)) or (|) a (, then [^()]*? matches any 0+ chars other than ( and ) chars, and then \K discards all the matched text and \+ matches a + that will be consumed and replaced. It still does not handle nested parentheses.

Also, see an online R demo for the above two solutions.

library(gsubfn)
s <- "(pop(+corn)+unicorn)-bread+salt+malt"
gsubfn("\\((?:[^()]++|(?R))*\\)", ~ gsub("+", "|", m, fixed=TRUE), s, perl=TRUE, backref=0)
## => [1] "(pop(|corn)|unicorn)-bread+salt+malt"

This solves the problem of matching nested parentheses, but requires the gsubfn package. See another regex demo. See this regex description here.

Note that in case you do not have to match nested parentheses, you may use "\\([^()]*\\)" regex with the gsubfn code above. \([^()]*\) regex matches (, then any zero or more chars other than ( and ) (replace with [^)]* to match )) and then a ).

Upvotes: 5

akrun
akrun

Reputation: 886948

We can try

sub("(\\([^+]+)\\+","\\1|", test)
#[1] "(pop|corn)-bread+salt"

Upvotes: 1

Related Questions