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);