-1

I coded an AJAX function to make a search engine in a database. I want to highlight in yellow the searched characters in the displayed result.

The following code is working pretty well:

$.ajax({
    type: "GET",
    url: "search_db.php",
    data: "q="+valueSearch,
    dataType: "JSON",
    success: function(returnQuery) {
        $("#table tbody").empty();
        // console.log(returnQuery);
        $.each(returnQuery, function(i, line) {
            content = '<tr>';
            content += '<td>' + line.name_serv + '</td>';
            content += '<td>' + line.name_dns + '</td>';
            content += '<td>' + line.ip + '</td>';
            content += '<td>' + line.pass1 + '</td>';
            content += '<td>' + line.pass2 + '</td>';
            content += '</tr>';

            re = new RegExp('('+valueSearch+')', "gi")
            content2 = content.replace(re, '<span style="background-color: #ffff66;">$1</span>');

            $(content2).appendTo("#table tbody");
        });
    }, 
    error: function() {
        $("#table tbody").empty();
    }
});

There are three cases where it doesn't work properly: if I search 'd', 't' or 'r' (because the remplacements are made in the <td> or <tr> markups too).

Here is an example of the variable content:
"<tr><td>Jupiter</td><td>mail.test.com</td><td>10.0.0.1</td><td>root</td><td>a$01'deK</td></tr>"

I try to make a RegExp to add the <span> markup only to characters matching the search between <td> and </td>, but I don't find the right syntax.

Does anyone have an idea (pure JavaScript and/or jQuery)?

pihug12
  • 317
  • 3
  • 14
  • 3
    Rule 1: don't use RegEx to parse HTML. Rule 2: if you still want to parse HTML with RegEx, see rule 1. [RegEx can only match regular languages, and HTML is not a regular language](http://stackoverflow.com/a/590789/930393) – freefaller Oct 21 '14 at 11:55
  • Further to @freefaller's comment and not doing this with regex: You're already using jQuery, so a good approach would be to wrap up `content` and use jQuery functionality to handle this: `$(content).find(....)` etc. – James Thorpe Oct 21 '14 at 12:03
  • Why are you not matching the text when you are building the cells? – epascarello Oct 21 '14 at 12:25
  • 1
    @freefaller He doesn't want to parse HTML, he wants to perform replacements everywhere but in tags, and regexes are an appropriate tool for that. Besides, modern regexes aren't regular anymore. – Lucas Trzesniewski Oct 21 '14 at 12:27

2 Answers2

1

My advice would be to run the regular expression BEFORE embedding the lines into td's, and do it on each line individually. I would create a function inside of the ajax call like this:

highlightMatches(line, valueSearch))
{

re = new RegExp('('+valueSearch+')', "gi")
line2 = line.replace(re, '<span style="background-color: #ffff66;">$1</span>');

  return line2;
}



line.name_serv = highlightMatches(line.name_serv, valueSearch)
line.name_dns  = highlightMatches(line.name_dns, valueSearch)
.
.
.
.

THEN I'd wrap each of the lines into content just as you've done.

That's my approach at least.

Ben Shumway
  • 70
  • 10
  • I chose this solution, thanks! It was the easiest one and it answers my need. `valueSearch` must be a parameter of the function though (I called the function like this: `highlightMatches(line.name_serv, valueSearch)`). – pihug12 Oct 22 '14 at 11:48
  • Thanks! I had fun writing it. Also thanks for the upgrade, I'll edit the code to match your function. – Ben Shumway Oct 23 '14 at 06:27
0

Here's a simplified approach to highlight all occurences of t outside of tags:

content = content.replace(/<.*?>|(t)/gi, function(match, captured) {
  if (!captured)
    return match;

  return '<span class="hl">' + captured + '</span>';
});

You can easily generalize this approach, just don't forget to escape the regex metacharacters:

function highlightTextInHtml(content, search) {
  // Escape regex metacharacters
  search = search.replace(/[-\\()\[\]{}^$*+.?|]/g, '\\$&');
  
  // Build the regex
  var re = new RegExp("<.*?>|(" +search+ ")", "gi");
  
  // Highlight matches
  return content.replace(re, function(match, captured) {
    if (!captured)
      return match;

    return '<span class="hl">' + captured + '</span>';
  });
}

$(document).on("ready", function() {
  var originalContent = $("#content").html();

  $("#search").on("keyup", function() {
    $("#content").html(highlightTextInHtml(originalContent, $("#search").val()));
  }).triggerHandler("keyup");
});
td { border: 1px solid black; }
.hl { background-color: yellow; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div>
    Search for: <input type="text" id="search" value="t"/>
</div>

<div id="content">
  <table>
    <tr><td>Jupiter</td><td>mail.test.com</td><td>10.0.0.1</td><td>root</td><td>a$01'deK</td></tr>
  </table>
</div>
Lucas Trzesniewski
  • 50,214
  • 11
  • 107
  • 158
  • I'm sorry, I didn't try your answer because @Benshums's one seems easier to me. Thanks a lot for the effort though! – pihug12 Oct 22 '14 at 11:50
  • No worries, his approach is better in your case. I posted this to answer the question *literally*, it could be useful for people who have a HTML string from an external source for instance. – Lucas Trzesniewski Oct 22 '14 at 11:58
  • But you still should add `valueSearch = valueSearch.replace(/[-\\()\[\]{}^$*+.?|]/g, '\\$&');` to his solution to escape the metacharacters, especially if `valueSearch` comes from an external source like user input: try searching for `a$01`. – Lucas Trzesniewski Oct 22 '14 at 12:00