1

I've got a script from a friend, and tried to modified it. So that it highlights a string of numbers in a div.

The problem is, that the output of the highlighted text becomes the regexp. Any solutions, what I'm doing wrong?

var list = document.getElementsByClassName("message__content")
var search_word = RegExp(/9756[0-9]{8}/);

var contents = []


for(var i = 0; i < list.length; i++){
var contents = list[i].textContent.split(search_word)


var elem = '<span class="highlight">'+search_word+'</span>'
list[i].innerHTML = contents.join(elem)
}

https://jsfiddle.net/rrggrr/kgd4swha/6/

RRG
  • 45
  • 1
  • 6

1 Answers1

3

Here's a simple way of doing it:

Use a string#replace using /(9756[0-9]{8})/g as the regex to capture the value (don't forget the g to indicate that it's a global regex so it'll run for every match in the input string), then a replace of '<span class="highlight">$1</span>' to use the first capture group and apply the markup.

var list = document.getElementsByClassName("message__content")

for (var i = 0; i < list.length; i++) {
  list[i].innerHTML = list[i].textContent.replace(
    /(9756[0-9]{8})/g,
    '<span class="highlight">$1</span>')
}
.highlight {
  color: blue;
}
<div class="message__content">
  Lorem ipsum dolor sit amet, 975600000000 (random quis) adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore 975611111111 . Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
  aute irure dolor in 975622222222 in voluptate velit esse cillum dolore eu fugiat nulla pariatur. (random quis) 975633333333 sint occaecat (random quis) cupidatat non proident, sunt in culpa qui officia des (random quis) nt mollit anim id est laborum.
</div>

As a note, the problem in the original post is that the string#split function doesn't actually save the text that was removed as part of the split, so if you wanted to go that route, you'd have to use string#matchAll on the side, and then map over the indexes to put everything together properly.

I took a look at doing this originally before I realized that string#replace is a cleaner solution in this instance.


From a comment, here's a way to conditionally set button classes based on if a regex matches.

If the goal is to check if every number in the text matches the regex, then we can use a regex replace for /\d+/g with a function as the replacement value so that we can do the regex#test within the replacement.

If you want to limit the numbers that get checked, you could modify the /d+/g to change what are being replaced.

var list = document.getElementsByClassName("message__content")

for (var i = 0; i < list.length; i++) {
  let text = list[i].textContent;
      // Make the regex have boundary characters to ensure that it's checking against the whole number, rather than a part
  const regex = /\b9756[0-9]{8}\b/;
  list[i].innerHTML = text.replace(
    // Replace all number sequences in the text
    /\d+/g,
    // Replace by checking if the replacement text matches the regex to determine color
    (match) => `<button class="${regex.test(match)}">${match}</button>`
  )
}
.highlight {
  color: blue;
}

.true {
  background-color: green;
}

.false {
  background-color: red;
}
<div class="message__content">
  Lorem ipsum dolor sit amet, 975600000000 (random quis) adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore 975611111111 . Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
  aute irure dolor in 975622222222 in voluptate velit esse cillum dolore eu fugiat nulla pariatur. (random quis) 975633333333 sint occaecat (random quis) cupidatat non proident, sunt in culpa qui officia des (random quis) nt mollit anim id est laborum.
  975600000000, 9756000000009, 097560000000, 9756000
</div>

Another possibility intead of checking every number is to split on a value and then map over the resulting values. I'm just including this as it's helpful for something that's simple to split.

var list = document.getElementsByClassName("message__content")

for (var i = 0; i < list.length; i++) {
  // split by ', ' as that is what is separating between values
  const values = list[i].textContent.split(', ');
  // Make the regex have boundary characters to ensure that it's checking against the whole number, rather than a part
  const regex = /\b9756[0-9]{8}\b/;
  list[i].innerHTML = values.map((value) => {
    // Loop over the split values and create buttons based on if the regex is a match against the string
    return `<button class="${regex.test(value)}">${value}</button>`
  }).join(', ');
}
.true {
  background-color: green;
}

.false {
  background-color: red;
}
<div class="message__content">
  975600000000, 9756000000009, 097560000000, 9756000
</div>
Zachary Haber
  • 10,376
  • 1
  • 17
  • 31
  • Thank you! I still have a question - if you could elaborate some more. If I want to add a true/false regex match. Match regex = green css. https://jsfiddle.net/rrggrr/pw956cou/4/ – RRG Oct 09 '20 at 22:45
  • I'm not entirely sure what you are asking here, sorry. Do you mean that all the string that isn't matched should be red, while all the string that is should be green? https://jsfiddle.net/urcg8z62/ – Zachary Haber Oct 09 '20 at 22:48
  • Excuse me, let me explain it better. I want to show all values 'starting with 9756 and having total of 12 numbers' to show a green button; all the rest of the buttons with incorrect value to be red. Now I have the problem with the buttons '9756000000009' (13 numbers, part is green) '097560000000 (12 numbers, but starts with 0) '9756000' (7 numbers). – RRG Oct 09 '20 at 22:57
  • 1
    @RRG, I updated the post with some possible ways of doing what you were asking. Hope this helps! – Zachary Haber Oct 09 '20 at 23:41
  • thanks for the full explanation. Really helpful! There's just one thing I'm still curious of. When we click on a red or green button, I want to copy that value (975600000000) to my clipboard. I think every button now also needs a var $1 id to every single made button now. – RRG Oct 10 '20 at 08:36
  • Have found this solution. https://jsfiddle.net/rrggrr/0xytwz45/14/. Could this code made cleaner? And maybe notify a small alert or something showing 'copied!' – RRG Oct 10 '20 at 10:28
  • 1
    Yeah, that's about the normal way of copying text, it's pretty awful, though there is a newer api for it [clipboard api](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText). I added that to this https://jsfiddle.net/9h4bc3u5/1/, but it won't work on the fiddle due to how things are set up. I also modified what you had but changed things to not use jquery: https://jsfiddle.net/9h4bc3u5/. As for a copy alert, it's more complicated to add anything other than an `alert()` call. – Zachary Haber Oct 10 '20 at 21:26
  • Thanks for clarifying! I still get the error "Uncaught ReferenceError: copyData is not defined at HTMLButtonElement.onclick" when I use the script inside Chrome Extension with permission "clipboardWrite", "clipboardRead". jsfiddle has no problem. What is that problem? I like the fact to use no jquery! – RRG Oct 10 '20 at 22:16
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/222838/discussion-between-zachary-haber-and-rrg). – Zachary Haber Oct 10 '20 at 22:18
  • @zachery https://stackoverflow.com/questions/64305663/multiple-regex-const-add-style-for-each-matched-word – RRG Oct 11 '20 at 15:24