1

I'm trying to highlight all the words that have more than 5 characters within a <p> element. I was able to select those words, but I failed on highlighting those words on the screen. I'd appreciate any help. Please see the complete code JavaScript exercise

    let pElement = document.getElementById("text");

function highlightLongWords(element){

    let paragraph = pElement.textContent;
    let textInsideP = pElement.innerHTML = paragraph;


    // use String.split(" ") to split the paragraph into an array of words
    let words = paragraph.split(" ");

    console.log(words);

    let longestWord = "abcde";
    //use Array.length to get the length of the array.

    for(let word of words) {
        if (word.length > longestWord.length) {
            //console.log(word);
            let longWords = word;
            
            pElement.style.backgroundColor = "yellow"
            console.log(longWords);

            
            
        } 
    }

    return;
    
}

highlightLongWords(pElement);
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Danny O.
  • 9
  • 2
  • 1
    You are “highlighting” the complete paragragh element all the time, with `pElement.style.backgroundColor = "yellow"`. If you want to be able to highlight individual words - then you need to wrap those into their own, individual HTML element each first. – CBroe Aug 24 '20 at 14:19
  • Does this answer your question? [How to highlight text using javascript](https://stackoverflow.com/questions/8644428/how-to-highlight-text-using-javascript) – Heretic Monkey Aug 24 '20 at 14:20

3 Answers3

1

You can use a regex to replace the text content of the p element such that every text segment which matches your criteria is replaced with that same content, but wrapped within a <span> element:

let wrapTextInSpans = (elem, regex) => {
  // Takes an element, and a regex. The regex should have the "g" flag set
  elem.innerHTML = elem.innerHTML.replace(regex, '<span>$&</span>');
};
wrapTextInSpans(document.querySelector('p'), /[a-zA-Z]{5,}/g);
.highlight > span {
  background-color: rgba(255, 0, 0, 0.2);
}
<p class="highlight">
  Hello, this is some sample text I have written for the illustrative purpose of detecting all
  linguistic words whose length is equal to or longer than five characters. I hope that this
  sample text combined with the accompanying javascript and css code is sufficient to solve
  your problem.
</p>

The regex used is very simple:

[a-zA-Z]       -> Any alpha character
        {5,}   -> Repeat minimum 5 times

If you want multiple consecutive words which match your criteria to share the same highlighting, you can simply extend the regex used for wrapTextInSpans:

let wrapTextInSpans = (elem, regex) => {
  // Takes an element, and a regex. The regex should have the "g" flag set
  elem.innerHTML = elem.innerHTML.replace(regex, '<span>$&</span>');
};
wrapTextInSpans(document.querySelector('p'), /[a-zA-Z]{5,}([^a-zA-Z]*[a-zA-Z]{5,})*/g);
.highlight > span {
  background-color: rgba(255, 0, 0, 0.2);
}
<p class="highlight">
  Hello, this is some sample text I have written for the illustrative purpose of detecting all
  linguistic words whose length is equal to or longer than five characters. I hope that this
  sample text combined with the accompanying javascript and css code is sufficient to solve
  your problem.
</p>

The regex used is a bit more complicated:

[a-zA-Z]                                 -> Alpha character
        {5,}                             -> Repeat minimum 5 times
            (                      )*    -> Repeat any number of times (including 0)
             [^a-zA-Z]*                  -> Any number of non-alpha characters (allowing punctuation to break up matching words)
                       [a-zA-Z]{5,}      -> 5 or more alpha characters
Gershom Maes
  • 7,358
  • 2
  • 35
  • 55
  • ... for the first approach I would use a more generic regex that does treat `-`-connected words as an entity ... `[\w-]{5,}`, whereas for the second approach I would go with something simpler that just optionally repeats the first base pattern while taking separating whitespace sequences into account as well ... [`(?:[\w-]{5,})(?:\s+[\w-]{5,})*`](https://regex101.com/r/zkp8BA/1). – Peter Seliger Aug 24 '20 at 21:12
  • For sure! Depending on what you define as "word", there are a number of bespoke regex solutions available here! – Gershom Maes Aug 24 '20 at 22:01
  • ... agreed. It was not meant to correct you but to show exactly the possible variety without adding another answer since your regex/replace-approach already does the job. – Peter Seliger Aug 24 '20 at 22:10
  • Hi, thank you for sharing this approach, I almost never use regex but I can see it makes sense to use it in this situation. I found a different solution yesterday, I"ll post it below. – Danny O. Aug 25 '20 at 17:48
0

Here I wrote small helper function for your case, check it and read comments

// Highlight function
const hl = (s, e) => {
  // Shortcut <p>
  const p = document.getElementById("myText");
  // Get content of target <p>
  let text = p.textContent;
  // Write custom replace function
  text = text.replace(new RegExp('(\\w+)', 'g'), (m) => {
    // Check if word is equal or greater or
    // has maximum parameter
    if(m.length >= s && (e && m.length <= e || !e)) return `<span class="yellow">${m}</span>`;
    else return m;
  });
  // Replace <p> with altered text
  p.innerHTML = text;
}

// Test by providing target length+ 
// BONUS: as second parameter you can pass
// maximum length, i.e: hl(6, 9);
hl(6);
.yellow {
  background-color: yellow;
}
<p id="myText">
JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions. While it is most well-known as the scripting language for Web pages, many non-browser environments also use it, such as Node.js, Apache CouchDB and Adobe Acrobat.
</p>
tarkh
  • 2,424
  • 1
  • 9
  • 12
  • Hi, there! I found a solution yesterday, I'll post it below. Thank you for sharing your solution, I'll take a look and try to implement it as an alternative, I've only used regex a couple of times and It didn't come to my mind as a possible solution. Thank you for your insight on this. – Danny O. Aug 25 '20 at 17:51
-1

everyone. Thank you for taking the time to reply to my question. It's been very valuable to see different solutions.

My solution was a bit simple since I was not familiar with regex. I used the .split() method to convert the text into an array, and I went with a for loop to identify the long words and wrap those with mark elements to highlight them.

let pElement = document.getElementById("text");

function highlightLongWords(element){

let longestWord = "abcde";
const words = element.textContent.split(" ");

for(let i = 0 ; i < words.length; i++){

    if(words[i].length > longestWord.length){

        element.innerHTML = element.innerHTML.replace(words[i],`<mark>${words[i]}</mark>`)

    }
}  

return;
}

highlightLongWords(pElement);
<p id="text">
  This sample text has highlighted words. Why are some words highlighted and others are not? Well, the highlighted words are 5 characters long, or longer. The non-highlighted words are shorter than 5 characters long.
</p>
Danny O.
  • 9
  • 2
  • This will fail to highlight duplicate words (the logic will always highlight the first instance of the word). I've edited your code to make it runnable; notice that not every instance of the word `words` is highlighted. – Gershom Maes Aug 25 '20 at 18:03
  • Additionally, this code may wind up wrapping a single word in multiple layers of `` – Gershom Maes Aug 25 '20 at 18:08
  • I haven't thought about highlighting duplicates. Thank you very much for your help! – Danny O. Aug 25 '20 at 18:14
  • You may also notice that `long.` is considered 5 characters long, which is probably better to avoid! – Gershom Maes Aug 25 '20 at 19:32