4

I want to match certain lines inside any text and inside that match, I want to replace a certain character as often, as it occurs. Sample Text:

Any text and "much" "more" of it. Don't replace quotes here
CatchThis( no quotes here, "any more text" , "and so on and so forth...")
catchthat("some other text" , "or less")
some text in "between"
CatchAnything ( "even more" , "and more", no quotes there, "wall of text")
more ("text"""") and quotes after...

Now I want to replace every quote inside the round brackets with, lets say, a hash sign. Desired outcome:

Any text and "much" "more" of it. Don't replace quotes here
CatchThis( no quotes here, #any more text# , #and so on and so forth...#)
catchthat(#some other text# , #or less#)
some text in "between"
CatchAnything ( #even more# , #and more#, no quotes there, #wall of text# )
more ("text"""") and quotes after...

Matching the lines is easy. Here's my pattern for that:

(?i)Catch(?:This|That|Anything)[ \t]*\(.+\)

Unfortunately, I have no idea how to match every quote and replace it...

TheFriesel
  • 81
  • 1
  • 5

2 Answers2

6

The common approach to matching all occurrences of some pattern inside 2 different delimiters is via using \G anchor based regular expression.

(?i)(?:\G(?!\A)|Catch(?:This|That|Anything)\s*\()[^()"]*\K"

See the regex demo.

Explanation:

  • (?i) - case insensitive modifier
  • (?: - a non-capturing group matching 2 alternatives
    • \G(?!\A) - a place in the string right after the previous successful match (as \G also matches the start of the string, the (?!\A) is necessary to exclude that possibility)
    • | - or
    • Catch(?:This|That|Anything) - Catch followed with either This or That or Anything
    • \s* - 0+ whitespaces
    • \( - a literal ( symbol
  • ) - end of the non-capturing group
  • [^()"]* - any 0+ chars other than (, ) and "
  • \K - a match reset operator
  • " - a double quote.
Graham
  • 6,577
  • 17
  • 55
  • 76
Wiktor Stribiżew
  • 484,719
  • 26
  • 302
  • 397
  • 1
    Very nice! Just what the doctor ordered. Working perfectly...and big thx for the explanation! – TheFriesel Jun 14 '17 at 06:42
  • 1
    Just in case you need to match multiple tokens in between *multi*character delimiters, I can advise using a ["tempered greedy token"](https://stackoverflow.com/a/37343088/3832970) instead of a negated character class (here, `[^()"]*` is used). – Wiktor Stribiżew Jun 14 '17 at 06:47
  • Thanks for the heads up! I'll look it up, but first, I have to fully understand your pattern ;) – TheFriesel Jun 14 '17 at 07:00
  • 1
    Please let me know which parts confuse you and I will update the answer. – Wiktor Stribiżew Jun 14 '17 at 07:00
  • Much appreciated, Wiktor! I get the single parts, just the whole pattern has not sunk in (yet). Atm, I don't think, I could come up with such a solution by my self, but give it time ;) – TheFriesel Jun 14 '17 at 07:25
0

Do you really need to replace this inside regex? If your regex finds what you want, you can replace character on found string

Pablo notPicasso
  • 2,923
  • 3
  • 15
  • 22
  • That's, what I'm doing right now: get an array of matches, replace the quotes and inject the modified matches back into the original text. Its pretty elaborate and I though, directly replacing inside the matches is much more elegant and maybe faster... – TheFriesel Jun 14 '17 at 06:16