How to refine that regex which skips one of two words?

Viewed 66

I have a text and I want to change all comprata, comprate, comprati, comprato to comprat+ and all ricomprata, ricomprate, ricomprati, ricomprato to ricomprat+. So I wrote this regex but it skips one of two words:

testo <- 'ricomprate uno comprato comprata due comprate ricomprate tre ricomprato comprati'
base::gsub('(\\s|^)(ri|)comprat[aeio](\\s|)', '\\1\\2comprat+\\3', testo)

The result is:

"ricomprat+ uno comprat+ comprata due comprat+ ricomprate tre ricomprat+ comprati"
3 Answers

As a pattern you might use

\b((?:ri)?comprat)[aeio]\b
  • \b A word boundary to prevent a partial match
  • ( Capture group 1 (Referred to as \\1 in the replacement)
    • (?:ri)? Optionally match ri
    • comprat Match comprat
  • ) Close group 1
  • [aeio] Match any of the listed chars
  • \b A word boundary

Regex demo | R demo

In the replacement use group 1 and a +

testo <- 'ricomprate uno comprato comprata due comprate ricomprate tre ricomprato comprati'
base::gsub('\\b((?:ri)?comprat)[aeio]\\b', '\\1+', testo)

Output

[1] "ricomprat+ uno comprat+ comprat+ due comprat+ ricomprat+ tre ricomprat+ comprat+"

Your regex does not work due to the trailing (\s|) pattern that consumes a whitespace and prevents consecutive matches.

You can use a PCRE regex like

testo <- 'ricomprate uno comprato comprata due comprate ricomprate tre ricomprato comprati'
gsub('(?<!\\S)((?:ri)?comprat)[aeio](?!\\S)', '\\1+', testo, perl=TRUE)
[1] "ricomprat+ uno comprat+ comprat+ due comprat+ ricomprat+ tre ricomprat+ comprat+"

See this regex demo. Details:

  • (?<!\S) - left-hand whitespace boundary
  • ((?:ri)?comprat) - Group 1: an optional ri string and then comprat
  • [aeio](?!\S) - either e, a, i or o followed with right-hand whitespace boundary

Or, a TRE regex like

testo <- 'ricomprate uno comprato comprata due comprate ricomprate tre ricomprato comprati'
gsub('\\b((?:ri)?comprat)[aeio]\\b', '\\1+', testo)
## => [1] "ricomprat+ uno comprat+ comprat+ due comprat+ ricomprat+ tre ricomprat+ comprat+"

See the R demo online and this regex demo, where \b stands for a word boundary.

base::gsub('comprat[aeio]', 'comprat+', testo)

Output

[1] "ricomprat+ uno comprat+ comprat+ due comprat+ ricomprat+ tre ricomprat+ comprat+"
Related