twharmon
twharmon

Reputation: 4272

Apply regex replace only within "scope"

How can I apply regex only within a certain scope, like between two **'s?

I want to use JavaScript to change this

**
    _a_ _b_ _c_
    -d- -e- -f-
**
_a_

into this

**
    {a} {b} {c}
    (d) (e) (f)
**
_a_

Notice that the desired result is that _a_ is not changed outside of the "scope".

I can do this much

str
    .replace(/_(.*?)_/g, "{$1}")
    .replace(/-(.*?)-/g, "($1)")

but this will replace everywhere, even outside of the two **'s.

Upvotes: 3

Views: 412

Answers (3)

Konard
Konard

Reputation: 3024

It was important to me to be able to make scoping with single regular expression. So it actually possible, thanks to lookbehind.

var str = `**
    _a_ _b_ _c_
    -d- -e- -f-
**
_a_`;


var pattern1 = /(\*\*((?<!\*\*).|\n)*?)_(.*?)_((.|\n)*?\*\*)/g;
var pattern2 = /(\*\*((?<!\*\*).|\n)*?)-(.*?)-((.|\n)*?\*\*)/g;

var result = str;

while(result.match(pattern1) != null)
{
    result = result.replace(pattern1, "$1{$3}$4");
}
while(result.match(pattern2) != null)
{
    result = result.replace(pattern2, "$1($3)$4");
}

console.log(result);

Upvotes: 0

Kevin B.
Kevin B.

Reputation: 1363

I would use the same or an simular solution as @choz does:

var str = "_a_\n**_a_ _b_ _c_\n-d- -e- -f-** \n_a_ \n**_a_ _b_ _c_-d- -e- -f-**_a_";

// split into parts
var parts = str.split(/(\*\*)/);

var shouldReplace = false;
var buffer = "";


// go tough all values
parts.forEach((value) => {

  // negate shouldReplace if delimter
  if (value === "**") {
    buffer += value;
    shouldReplace = !shouldReplace;
    return;
  }

  // if not shouldReplace add to buffer
  if (!shouldReplace) {
    buffer += value;
    return;
  }

  // replace the value if shouldReplace
  buffer += value
              .replace(/_(.*?)_/g, "{$1}")
              .replace(/-(.*?)-/g, "($1)")
});

console.log(buffer);

Upvotes: 0

choz
choz

Reputation: 17858

One way to achieve this and it's simpler for me is to extract the string inside your delimiter **, and replace it with your existing regexes (which already works).

E.g.

var str = `**
    _a_ _b_ _c_
    -d- -e- -f-
**
_a_`;

var result = str.replace(/\*\*(\s|.)+\*\*/g, function (x) {
	return x
           .replace(/_(.*?)_/g, "{$1}")
           .replace(/-(.*?)-/g, "($1)");
});

console.log(result);

Upvotes: 4

Related Questions