MirrorMirror
MirrorMirror

Reputation: 188

javascript regex, word not followed and not preceded by specific char

I guess I'm not very good at regular expressions, so here is my problem (I'm sure it's easy to solve, but somehow I can't seem to find how )

var word = "aaa";
text = text.replace( new RegExp(word, "g"),
                     "<span style='background-color: yellow'>"+word+"</span>");

this is working in most cases.

What I want to do is for the regex ONLY TO WORK when word is not followed by the char / and not preceded with char ".

Upvotes: 8

Views: 10854

Answers (3)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626689

First of all, the question can be interpreted as

  1. match word not preceded AND not followed ("aaa and aaa/ should match, same as "aaa/) and as
  2. match word not preceded OR not followed with some char(s) ("aaa, aaa/ should not match, while "aaa/ should).

If you are using a JavaScript environment that supports ECMAScript 2018, you can use a lookbehind solution:

const word = 'aaa',                     // Word to find
    left = '"',                         // Left-hand negative marker
    right = '/',                        // Right-hand negative marker
    text = 'aaa aaa/ "aaa "aaa/ aaaaa'; // Test string

// Relace any 'word' that does not start with " OR does not end with /
var regex = new RegExp(String.raw`\b(?<!${left})${word}\b(?!${right})`, 'g')
console.log( text.replace(regex, "<span style='background-color: yellow'>$&</span>") );
// => <span style='background-color: yellow'>aaa</span> aaa/ "aaa "aaa/ aaaaa

// Replace any 'word' that does not start with " AND does not end with /
var regex = new RegExp(String.raw`\b${word}\b(?!(?<=${left}${word})${right})`, 'g')
console.log( text.replace(regex, "<span style='background-color: yellow'>$&</span>") );
// => <span style='background-color: yellow'>aaa</span> <span style='background-color: yellow'>aaa</span>/ "<span style='background-color: yellow'>aaa</span> "aaa/ aaaaa

If you are using a JavaScript environment that does not support ECMAScript 2018, you can use

var word = 'aaa',                       // Word to find
    left = '"',                         // Left-hand negative marker
    right = '/',                        // Right-hand negative marker
    text = 'aaa aaa/ "aaa "aaa/ aaaaa'; // Test string

// Relace any 'word' that does not start with " OR does not end with /, one match expected
var regex = new RegExp("([^" + left + "\\w]|^)(" + word + ")\\b(?!" + right + ")", 'g')
console.log( text.replace(regex, "$1<span style='background-color: yellow'>$2</span>") );
// => <span style='background-color: yellow'>aaa</span> aaa/ "aaa "aaa/ aaaaa

// Same as above, but in case "left" is a sequence of chars, not a single char, or a longer pattern:
var regex = new RegExp("(" + left + ")?\\b(" + word + ")\\b(?!" + right + ")", 'g')
console.log( text.replace(regex, function(x,g,gg) { return g ? x : "<span style='background-color: yellow'>" + gg + "</span>";}) );
// => <span style='background-color: yellow'>aaa</span> aaa/ "aaa "aaa/ aaaaa

// Replace any 'word' that does not start with " AND does not end with /, three matches expected
var regex = new RegExp("(" + left + word + right + ")|\\b" + word + "\\b", 'g')
console.log( text.replace(regex, function(x, g) { return g || "<span style='background-color: yellow'>" + x + "</span>";}) );
// => <span style='background-color: yellow'>aaa</span> <span style='background-color: yellow'>aaa</span>/ "<span style='background-color: yellow'>aaa</span> "aaa/ aaaaa

Note:

  • I use whole word matching here via \b, word boundary (and \w construct in the negated character class in one of the workarounds)
  • If right and left chars/strings contain special regex metacharacters, mind to escape them before using as part of a regex
  • Same escaping need might arise for the word variable, but in that case, if the word starts or/and ends with a special regex metacharacter, word boundaries (\b) will no longer work, you will need to use adaptive/dynamic word boundaries.

Upvotes: 0

Michael
Michael

Reputation: 3332

You're going to want to use a negative look-ahead.

Regex: '[^"]' + word + '(?!/)'

Edit: While it doesn't matter as it appears you already found your answer by avoiding look-behinds, Rohit noticed something I didn't. You're going to need to capture the [^\"] and include it in the replace so that it does not get discarded. This wasn't necessary for the look-head since look-arounds by definition aren't included in captures.

Upvotes: 15

Rohit Jain
Rohit Jain

Reputation: 213203

You can use this regex: -

'([^"])' + word + '(?!/)'

and replace it with - "$1g"

Note that Javascript does not support look-behinds. So, you need to capture the previous character and ensure that it is not ", using negated character class.

See demo at http://fiddle.re/zdjt

Upvotes: 4

Related Questions