0

I have a string containing curly brackets and I want to replace any character A, which is not contained in a pair of opening and closing brackets, by another character B. So

ABCDACD{ACDA}ABCD

should be replaced by

BBCDBCD{ACDA}BBCD

How can I do this with a regex (e.g. in Perl)? Brackets are not nested, but a solution working also for the nested case would be better.

EDIT: Changed wording

  • Non-nested: `A(?![^{}]*\})` - check that the next bracket after A (if any) is not a closing one. Now let me look for a good dupe. – Sebastian Proske Mar 15 '17 at 12:30
  • Possible duplicate of [Regular Expression, match characters outside curly braces { }](http://stackoverflow.com/questions/14032016/regular-expression-match-characters-outside-curly-braces) – Sebastian Proske Mar 15 '17 at 12:33
  • *"a solution working also for the nested case would be better"* Why, if your data doesn't have nested braces? A non-nested solution is straightforward, but a recursive pattern is necessary for nested braces. – Borodin Mar 15 '17 at 13:04
  • @NicolasMalebranche: would you please clarify does your statement _"I want to replace a character A by another character B, if it is not contained in a pair of opening and closing brackets."_ actually means _"if the replacement value B is inside the the braces then you don't replace A by B anywhere"_? – Dmitry Egorov Mar 15 '17 at 13:11
  • @NicolasMalebranche: what is the expected result of the `ABCDACD{ABCDA}ABCD` input string (please notice the `B` inside the brackets)? Should it be `BBCDBCD{ABCDA}BBCD` (all `A`s outside brackets replaced) or `ABCDACD{ABCDA}ABCD` (the original string unchanged)? – Dmitry Egorov Mar 15 '17 at 13:17

2 Answers2

2

A similar question has already been answered before.

Perl implementation will be different in substitution evaluation part but the main idea is the same:

Match undesired context (i.e. {.*?}) or desired substring (A) (in that particular order) using alternation capturing the matches. Then substitute the undesired capture with itself and the desired one with your replacement depending on which part has matched:

my $input = "ABCDACD{ACDA}ABCD";
$input =~ s/({.*?})|(A)/{$2 ? "B" : $1}/ge;

Demo: https://ideone.com/bK4c1Y

Community
  • 1
  • 1
Dmitry Egorov
  • 9,542
  • 3
  • 22
  • 40
  • Your regex is wrong , if B is inside the curly brace then it fails https://ideone.com/kPFT0G – Mustofa Rizwan Mar 15 '17 at 13:04
  • @RizwanM.Tuman, The output in your link is `BBCDBCD{ABCDA}BBCD`. What exactly is wrong there? – Dmitry Egorov Mar 15 '17 at 13:07
  • Op wrote : " I want to replace a character A by another character B, if it is not contained in a pair of opening and closing brackets." which means if the replacement value B is inside the the braces then you don't replace A by B anywhere – Mustofa Rizwan Mar 15 '17 at 13:08
  • 2
    @RizwanM.Tuman: I think you misunderstood, OP wants to replace `A` by `B` when `A` is not inside curlybrackets – Toto Mar 15 '17 at 13:11
  • So, I deleted the answer... feel like fool for the misleading question and lack of sample i/o :| – Mustofa Rizwan Mar 15 '17 at 13:22
1

Here is a Perl solution that does the job in steps. First it splits the string into chunks of braced/not braced items. Then does the substitution on the not-braced items, and finally puts the items back together again:

my $str = 'ABCDACD{ACDA}ABCD';
$str = do {
    my $i = 1; 
    join '', map {$i++ % 2 && $_ =~ s/A/B/g; $_ } split /(\{.*?\})/, $str 
};
Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174