2

I have this HTML code

<span class="line"><span>// Before</span></span> 
<span class="line">
  <span>import</span>
<span> </span><span>db</span>
<span> </span><span>from</span><span>    </span>
  <span>'../../lib/db-admin'</span><span>;</span>
</span> 
<span class="line"><span>// After</span></span> 
<span class="line"><span>import</span>
<span> </span><span>db</span><span> </span>
<span>from</span><span> </span>
<span>'lib/db-admin'</span><span>;</span></span>

I would like to replace every opening and closing span tag with class="line" with the div tag. How can i do it using regular expressions?

This is what i've already tried, but cannot get it until working condition.

/(<span class="line">.*?<\/span>)\s*<span class="line">(.*?)<\/span>((?!<\/span>).)*<\/span>/g, '$1</div><div class="line">$2</div>'
TylerH
  • 20,799
  • 66
  • 75
  • 101
Andrew
  • 1,507
  • 1
  • 22
  • 42
  • 4
    Don't [parse HTML with regex](https://stackoverflow.com/a/1732454/21363224). – markalex May 17 '23 at 19:31
  • 2
    Is there a reason you want to use regular expressions instead of (usually easier, and more straightforward) DOM manipulation? – David Thomas May 17 '23 at 20:13
  • I see what you're trying to do. You would like this ` // Before` to become this `
    // Before
    ` ?
    – sln May 17 '23 at 21:04
  • If that's the case, you'd have to get the nested _`spans`_ to find the closing span that corresponds to the open one with the class you need. This is easy to do with PCRE, BOOST or Dot-Net regex engines. Php uses PCRE so that'd be your best bet. I could give you a regex in 1 minute to do this if you decide to stray from JS – sln May 17 '23 at 21:09
  • Can you explain the larger context? Why do you need these `span` tags to be replaced with `div` tags? This sounds like a [XY problem](https://en.wikipedia.org/wiki/XY_problem). – trincot May 18 '23 at 07:32

1 Answers1

2

Don't use a regex to analyse/parse an HTML string. Instead use a DOM parser. You can use DOMParser and do this:

function replaceWithDivs(html, selector) {
    const doc = new DOMParser().parseFromString(html, "text/html");
    for (const elem of doc.querySelectorAll(selector)) {
        const div = doc.createElement("div"); // Create the new element
        div.innerHTML = elem.innerHTML;       // Copy the contents
        elem.replaceWith(div);                // And replace old with new
    }
    return doc.body.innerHTML;
}

// demo
let html = `<span class="line"><span>// Before</span></span> 
<span class="line">
  <span>import</span>
<span> </span><span>db</span>
<span> </span><span>from</span><span>    </span>
  <span>'../../lib/db-admin'</span><span>;</span>
</span> 
<span class="line"><span>// After</span></span> 
<span class="line"><span>import</span>
<span> </span><span>db</span><span> </span>
<span>from</span><span> </span>
<span>'lib/db-admin'</span><span>;</span></span>`;

html = replaceWithDivs(html, "span.line");
console.log(html);
trincot
  • 317,000
  • 35
  • 244
  • 286