Home > Software design >  replace text conditionally using regex and index
replace text conditionally using regex and index

Time:09-03

I'm writing a code where I'm getting rich text and want to replace things. Here I've 2 queries.

  1. How can I match *, **, and *** separately?
  2. How can I conditionally replace data? i.e. if the index of *** from match is 1 I want to have it replaced by _* else *_.

Here is my sample code.

let x =
  "Lorem ***ipsum*** dolor sit amet, consectetur adipiscing elit. Quod non faceret, si in voluptate summum bonum poneret. Ratio quidem vestra sic cogit. *Qui\\-vere falsone, quaerere mittimus\\-dicitur oculis se privasse;* Sed in rebus apertissimis ***nimium longi sumus. Eiuro, inquit adridens, iniquum, hac quidem de re; **Que Manilium, ab iisque M.** Quis animo aequo videt eum, quem inpure ***ac flagitiose putet vivere? Duo Reges: constructio interrete.";

var re = new RegExp(/(\*)(\*)(\*)/g);
var results = new Array(); //this is the results you want
for (let match of x.matchAll(re)) {
  results.push(match.index);
}

results.forEach((item, idx) =>
  idx % 2 === 0
    ? (x = replaceRange(x, item, item   3, "_*"))
    : (x = replaceRange(x, item, item   3, "*_"))
);

function replaceRange(s, start, end, substitute) {
  return s.substring(0, start)   substitute   s.substring(end);
}
console.log(x);

When I run this code, it is not replacing the data as expected. Please let me know where I'm going wrong.

Thanks

CodePudding user response:

One way is to use RexExp.prototype.exec, which is stateful and keeps track of the last match so you can iterate over each match. Then use a counter to keep track of how many matches you've found so you know whether to use *_ or _*.

let x =
  "Lorem ***ipsum*** dolor sit amet, consectetur adipiscing elit. Quod non faceret, si in voluptate summum bonum poneret. Ratio quidem vestra sic cogit. *Qui\\-vere falsone, quaerere mittimus\\-dicitur oculis se privasse;* Sed in rebus apertissimis ***nimium longi sumus. Eiuro, inquit adridens, iniquum, hac quidem de re; **Que Manilium, ab iisque M.** Quis animo aequo videt eum, quem inpure ***ac flagitiose putet vivere? Duo Reges: constructio interrete.";

const regex = new RegExp(/\*\*\*/g)
let result
let matchCount = 0
while(result !== null)
  {
    result = regex.exec(x)
    if (result === null) break
    matchCount  = 1
    matchCount % 2 === 0
      ? (x = replaceRange(x, result.index, result.index   3, "_*"))
      : (x = replaceRange(x, result.index, result.index   3, "*_"))
  }

console.log('x', x)

function replaceRange(s, start, end, substitute) {
  return s.substring(0, start)   substitute   s.substring(end);
}

CodePudding user response:

You can search for the same * pattern after and before each word with Backreference, which matches the same text as matched by the 1st capturing group. For instance, with triple asterisks as in ***, the regex could be:

[^_]([*]{3})(\w )\1

Using this replacement:

 _*$2*_

Explanation:

  • [^_]: avoids capturing if it starts with _
  • ([*]{3}): capture group that matches exactly 3 `*
  • (\w ): capture group that matches any word character at least once.
  • \1: backreference to the first capture group, it will capture its same match.

Regarding your queries, it depends on the replacements. Since the provided example _* also has an asterisk, you must adapt the regex so that it won't substitute the output of the previous regex.

let x =
  "Lorem ***ipsum*** dolor sit amet, consectetur adipiscing elit. Quod non faceret, si in voluptate summum bonum poneret. Ratio quidem vestra sic cogit. *Qui\\-vere falsone, quaerere mittimus\\-dicitur oculis se privasse;* Sed in rebus apertissimis ***nimium longi sumus. Eiuro, inquit adridens, iniquum, hac quidem de re; **Que Manilium, ab iisque M.** Quis animo aequo videt eum, quem inpure ***ac flagitiose putet vivere? Duo Reges: constructio interrete.";

const re1 = new RegExp(/[^_]([*]{1})(\w )\1/g);
const re2 = new RegExp(/([*]{2})(\w )\1/g);
const re3 = new RegExp(/[^_]([*]{3})(\w )\1/g);
 
let result = x.replaceAll(re3, " _*$2*_");

console.log(result);

  • Related