I'm writing a code where I'm getting rich text and want to replace things. Here I've 2 queries.
- How can I match
*,**, and***separately? - 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);
