Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Don't replace regex if it is enclosed by a character

I would like to replace all strings that are enclosed by - into strings enclosed by ~, but not if this string again is enclosed by *.

As an example, this string...

The -quick- *brown -f-ox* jumps.

...should become...

The ~quick~ *brown -f-ox* jumps.

We see - is only replaced if it is not within *<here>*.

My javascript-regex for now (which takes no care whether it is enclosed by * or not):

var message = source.replace(/-(.[^-]+?)-/g, "~$1~");

Edit: Note that it might be the case that there is an odd number of *s.

like image 383
poitroae Avatar asked Mar 28 '13 13:03

poitroae


People also ask

How do you negate a character in regex?

Similarly, the negation variant of the character class is defined as "[^ ]" (with ^ within the square braces), it matches a single character which is not in the specified or set of possible characters. For example the regular expression [^abc] matches a single character except a or, b or, c.

What does \+ mean in regex?

To match a character having special meaning in regex, you need to use a escape sequence prefix with a backslash ( \ ). E.g., \. matches "." ; regex \+ matches "+" ; and regex \( matches "(" . You also need to use regex \\ to match "\" (back-slash).

What is difference [] and () in regex?

[] denotes a character class. () denotes a capturing group. [a-z0-9] -- One character that is in the range of a-z OR 0-9.

Can regex replace characters?

RegEx can be effectively used to recreate patterns. So combining this with . replace means we can replace patterns and not just exact characters.


2 Answers

That's a tricky sort of thing to do with regular expressions. I think what I'd do is something like this:

var msg = source.replace(/(-[^-]+-|\*[^*]+\*)/g, function(_, grp) {
  return grp[0] === '-' ? grp.replace(/^-(.*)-$/, "~$1~") : grp;
});

jsFiddle Demo

That looks for either - or * groups, and only performs the replacement on dashed ones. In general, "nesting" syntaxes are challenging (or impossible) with regular expressions. (And of course as a comment on the question notes, there are special cases — dangling metacharacters — that complicate this too.)

like image 108
Pointy Avatar answered Oct 19 '22 18:10

Pointy


I would solve it by splitting the array based on * and then replacing only the even indices. Matching unbalanced stars is trickier, it involves knowing whether the last item index is odd or even:

'The -quick- *brown -f-ox* jumps.'
    .split('*')
    .map(function(item, index, arr) { 
        if (index % 2) {
            if (index < arr.length - 1) {
                return item; // balanced
            }
            // not balanced
            item = '*' + item;
        }
        return item.replace(/\-([^-]+)\-/, '~$1~');
    })
    .join('');

Demo

like image 42
Ja͢ck Avatar answered Oct 19 '22 16:10

Ja͢ck