1

What I want to do is turn this:

<DIV>One Two Three</DIV>

Into this:

HTML

<DIV><SPAN id="One"></SPAN><SPAN id="Two"></SPAN><SPAN id="Three"></SPAN></DIV>

CSS

#One { background-image: url('one.png'); }
#Two { background-image: url('two.png'); }
#Three { background-image: url('three.png'); }

I have a couple problems. First, I know the RegEx command:

\b\w(.*?)+\b

Will pick up every word in a string, but it inadvertently turns every instance of DIV into a match. I tried using positive lookups so that DIV is not picked up:

(?<=>)\b\w(.*?)+\b(?=<)

But it resulted in turning "One Two Three" into a unified match.

Secondly, I have this jQuery code that will turn my match criteria into SPAN IDs.

$("DIV").each(function() {
    $(this).html($(this).html().replace(/\b\w(.*?)+\b/gi, "<SPAN id=\"$0\"></SPAN>"));
});

But then I found Alex Turpin's answer to wrapping each word of an element inside a SPAN tag, and wanted to apply that. It almost worked: I was able to give each word in the string a SPAN element, but it would not preserve the id parameter. What am I missing to make this all work?

UPDATE: Anant provided a promising solution in the comments section. During my test, I ran into a weird bug where it picked up all instances of a placeholder string that was serving as a personal reminder to replace the word later. They look like this:

<DIV>
 <DIV class="Something">One Two Three</DIV></DIV>
<DIV>
 <DIV class="Something">TEMP</DIV></DIV>
<DIV>
 <DIV class="Something">TEMP</DIV></DIV>

When the code was applied, it turned into this:

<DIV>
 <DIV class="Something"><SPAN style="background-image: url(one.png)"></SPAN><SPAN style="background-image: url(two.png)"></SPAN><SPAN style="background-image: url(threeTEMPTEMP.png)"></SPAN></DIV></DIV>
<DIV>
 <DIV class="Something"><SPAN style="background-image: url(one.png)"></SPAN><SPAN style="background-image: url(two.png)"></SPAN><SPAN style="background-image: url(threeTEMPTEMP.png)"></SPAN></DIV></DIV>
<DIV>
 <DIV class="Something"><SPAN style="background-image: url(one.png)"></SPAN><SPAN style="background-image: url(two.png)"></SPAN><SPAN style="background-image: url(threeTEMPTEMP.png)"></SPAN></DIV></DIV>

This bug was solved by simply deleting all traces of the word TEMP from the HTML. You will also notice the code duplicating itself in every Something class. All that's left is for the code to take each instance of Something class individually.

Wammy
  • 39
  • 11
  • I don't know about RegEx, but maybe you can use this? `textContent.trim().split(' ')` then for each element you can create a span object and append it to `
    `
    – alph Apr 12 '23 at 03:13
  • 1
    For the Alex Turpin's solution, you just need to add `.attr("id", v)` when you create the span. See: https://jsfiddle.net/yr8wt0dg/ Unless you have very strict/specific html, [don't use a regex](https://stackoverflow.com/a/1732454/2181514). In your case, use `.text()` instead of `.html()`. – freedomn-m Apr 12 '23 at 05:41
  • 1
    Might be useful to know why you think you need to do this. Auto-generated *IDs* are generally of no use to anyone; there's probably a better way to do what you think this will solve (XY problem). – freedomn-m Apr 12 '23 at 06:05
  • I need the IDs so that I can tie them to the background-image property. Each word is connected to an image file (eg. one.png for One). I'm hoping this technique will save me from having to copy-paste multiple IMGs throughout the HTML. – Wammy Apr 12 '23 at 06:11
  • I'd suggest a `data-img='One'` attribute rather than an ID (or maybe just add to the class list). The solution would be the same, but would not potentially generate duplicate IDs or invalid IDs. – freedomn-m Apr 12 '23 at 06:15
  • It almost did. On the first two instances, it got them correctly. The third one added a word that I have no idea where it came from. Your code is close. (Apologies for the delay in reply, had to be sure it wasn't something on my end.) – Wammy Apr 12 '23 at 07:09
  • I do know why this is happening. So I have multiple DIVs like that in different groups. In each DIV, I added a placeholder as a reminder to replace that section later. Turns out the script picked up every instance of the placeholder word. I'll update the main post to show what I mean. – Wammy Apr 12 '23 at 07:20
  • Here's an updated fiddle using sample images (from another SO post): https://jsfiddle.net/e7o0vm1t/ – freedomn-m Apr 12 '23 at 07:21
  • Regarding code working on more html than intended - that's because you have `$("div")` - add a class to the divs that you want to apply to (`
    `) and change js to `$("div.background")` (for example) - so it only applies to the divs that you choose.
    – freedomn-m Apr 12 '23 at 07:22

2 Answers2

1

You are missing a regex that works:

\S   # Match           non-whitespace characters.
+    #       1 or more

Also, your replace string should use $& and not $0:

<span id="$&"></span>

Try it on regex101.com.

This is how your current regex works:

\b      # Match a word boundary
\w      # then a word character ('a' to 'z', lower or uppercase, '-', or a digit),
(       # then           groups, each consists of
  .*?   #                                         0 or more characters,
)+      #      1 or more
\b      # then ends with another word boundary.

Try it on regex101.com to see the difference between them.

Try it:

$('div').each(function() {
  const currentHTML = $(this).html();
  const newHTML = currentHTML.replace(
    /\S+/g,
    '<span id="$&"></span>'
  );
  
  console.log(currentHTML);
  console.log(newHTML);
  
  $(this).html(newHTML);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div>One Two Three</div>
InSync
  • 4,851
  • 4
  • 8
  • 30
1

Apply an extra class to the divs where you want to do the replacement work:

Check below code snippet:

$('div.modify-html').each(function() {
  var obj = $(this);
  var words = obj.text().split(" ");
  obj.empty();
  $.each(words, function(i, v) {
    var imgSrc = v.toLowerCase() + ".png";
    obj.append($("<span style='background-image: url(" + imgSrc + ");'>").text(v));
  });

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <div class="something modify-html">One Two Three</div>
</div>
<div>
  <div class="something">TEMP</div>
</div>
<div>
  <div class="something">TEMP</div>
</div>
<div>
  <div class="something modify-html">Four Five Six</div>
</div>
Alive to die - Anant
  • 70,531
  • 10
  • 51
  • 98