0

I am trying to find all commas between two words and replace them with another string in JS. I've tried literally every solution I've found but failed.

I have this HTML snippet (this is just a string looking like an html and not a real html document)

<style>
a,span{color:#29728D;text-decoration: underline;}
a:hover{ color:#69621C;text-decoration: underline;}
body, td{font-size:9pt; color:#333333}
</style>

<p>red, white, blue</p>

Now what I wanna do is replace those commas in the style tag with a random word such as "comma" or something.
But not replacing the commas in p or any other tags.

Closest I got was something like
(?<=(le>\w)*),+(?=\w|\W(<\/style>))

but did not work.

Any help would be appreciated.

Yoojin Kim
  • 37
  • 4
  • 3
    Please read [this answer](https://stackoverflow.com/a/1732454/1444609). Even Jon Skeet cannot parse HTML using regular expressions. – I wrestled a bear once. Aug 27 '20 at 12:36
  • @Iwrestledabearonce. to be clear, he's not trying to parse html, only to use regex on the innerhtml of a tag – jonatjano Aug 27 '20 at 12:37
  • 2
    @jonatjano - Look at his regex pattern. He is trying to parse HTML. – I wrestled a bear once. Aug 27 '20 at 12:38
  • @Iwrestledabearonce. look at the question, he doesn't want to modify the tag, only the content – jonatjano Aug 27 '20 at 12:39
  • 1
    @jonatjano - Who said anything about trying to modify the tag? He is parsing HTML with regex! If he had a reference to the element in the DOM and wanted to modify it's innerHTML that would be one thing, but the guy is trying to parse an HTML document as a string with regex. – I wrestled a bear once. Aug 27 '20 at 12:42
  • @Iwrestledabearonce. maybe the problem is that he doesn't know how to select element, nor how to modify their contents – jonatjano Aug 27 '20 at 12:43
  • The html tag I have is in string form so I'm not trying to parse html.. it's just string looking like an html – Yoojin Kim Aug 27 '20 at 12:45
  • you should have said that sooner, it change my answer – jonatjano Aug 27 '20 at 12:46
  • @Iwrestledabearonce. - wow, it's been years since I've seen Tony the Pony :p always makes me smile – Jaromanda X Aug 27 '20 at 12:48
  • What do you mean by "_it's just string looking like an html_". Your title mentions "_between two html tags_". Your string looks an awful lot like HTML. What part of it isn't? – Ivar Aug 27 '20 at 12:48
  • sorry i edited by question. i should have mentioned that it's just a string – Yoojin Kim Aug 27 '20 at 12:49
  • So, just because it's a string doesn't mean it's not parsable. Take a look at how Titus replaces the CSS selector for each rule. – Mr. Polywhirl Aug 27 '20 at 13:22
  • @Mr.Polywhirl No one is saying it's not parsable. It's just a bad idea ot try to do it with regex. You don't even need a DOM parser either. Look at my answer. – I wrestled a bear once. Aug 27 '20 at 13:39
  • @Iwrestledabearonce. I meant parsable in the sense of the built-in CSS rule parser; not text parsing. I am agreeing with you. Use an actual parser (API), not a regular expression. I was commenting on this from OP: _"it's just a string"_ – Mr. Polywhirl Aug 27 '20 at 13:47

3 Answers3

1

If you use DOM access you can change the content

const snippet = `<style>
a,span{color:#29728D;text-decoration: underline;}
a:hover{ color:#69621C;text-decoration: underline;}
body, td{font-size:9pt; color:#333333}
</style>

<p>red, white, blue</p>`

const domSnippet = document.createElement("x");
domSnippet.innerHTML=snippet;
const st = domSnippet.querySelector("style").textContent;
domSnippet.querySelector("style").textContent = st.replace(/,/g,"£££")
console.log(domSnippet.innerHTML);
<style>
a,span{color:#29728D;text-decoration: underline;}
a:hover{ color:#69621C;text-decoration: underline;}
body, td{font-size:9pt; color:#333333}
</style>

<p>red, white, blue</p>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
1

If I understand correctly, you're looking to modify the css selectors in that string. What you can do is parse the string as HTML, get the <style> element, modify its CSS rules (specifically the selectorText) and build a string from all the modified rules and set that as the new HTML content of the <style> element.

Here is an example:

const content = `<style>
a,span{color:#29728D;text-decoration: underline;}
a:hover{ color:#69621C;text-decoration: underline;}
body, td{font-size:9pt; color:#333333}
</style>

<p>red, white, blue</p>`

const doc = new DOMParser().parseFromString(content, 'text/html');
const style = doc.querySelector('style');

const result = [...style.sheet.cssRules]
  .reduce((acc, rule) => {
    rule.selectorText = rule.selectorText.replace(/\s*,\s*/g, ' comma ');
    acc += rule.cssText +'\n';
    return acc;
  }, '\n');


style.innerHTML = result;
const newContent = doc.head.innerHTML + '\n' + doc.body.innerHTML;

console.log(newContent);
Titus
  • 22,031
  • 1
  • 23
  • 33
  • Alright, this is the answer. **Note:** I would probably gobble the spaces surrounding the comma too: `/\s*,\s*/g` – Mr. Polywhirl Aug 27 '20 at 13:20
  • @Mr.Polywhirl I've added that but I don't think it is necessary because the `CSSStyleSheet` seems to format the `cssText` string to remove any extra unnecessary spaces. – Titus Aug 27 '20 at 13:23
  • Alright, sounds good. I get it, when you change the `selectorText`, the resulting `cssText` will auto-format anyways. – Mr. Polywhirl Aug 27 '20 at 13:32
0

Here's a solution that uses pure string functions. No regex, no DOM parsing. This method will be more robust than using DOMParser() because it can safely handle broken HTML without errors and it will work outside of a browser if you need it to.

const document_body = `<style>
a,span{color:#29728D;text-decoration: underline;}
a:hover{ color:#69621C;text-decoration: underline;}
body, td{font-size:9pt; color:#333333}
</style>

<p>red, white, blue</p>`;


var parsed, modified = document_body, current_index = -1;
while ((parsed = getTagContent(modified, '<style>', '</style>', current_index)) !== false) {
  let tag_contents = modified.substring(parsed.start, parsed.end);
  let modified_tag_contents = tag_contents.replace(/,/g, 'COMMA');
  modified = modified.substring(0, parsed.start) + modified_tag_contents + modified.substring(parsed.end);
  current_index = parsed.end - (modified_tag_contents.length - tag_contents.length);
}

console.log("Original: "+document_body);
console.log("Modifided: "+modified);

function getTagContent(html_body, start_tag, end_tag, start_index = 0) {
  var start = html_body.indexOf(start_tag, start_index);
  if (start === -1) return false;
  var end = html_body.indexOf(end_tag, start);
  if (end === -1) return false;
  return {
    start: start + start_tag.length,
    end
  };
}
I wrestled a bear once.
  • 22,983
  • 19
  • 69
  • 116