Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regex for visible text, not HTML

If i had a string:

hey <a href="#user">user</a>, what are you doing?

How, with regex could I say: look for user, but not inside of < or > characters? So the match would grab the user between the <a></a> but not the one inside of the href

I'd like this to work for any tag, so it wont matter what tags.

== Update ==

Why i can't use .text() or innerText is because this is being used to highlight results much like the native cmd/ctrl+f functionality in browsers and I dont want to lose formatting. For example, if i search for strong here:

Some <strong>strong</strong> text.

If i use .text() itll return "Some strong text" and then I'll wrap strong with a <span> which has a class for styling, but now when I go back and try to insert this into the DOM it'll be missing the <strong> tags.

like image 496
Oscar Godson Avatar asked Jun 23 '11 06:06

Oscar Godson


3 Answers

If you plan to replace the HTML using html() again then you will loose all event handlers that might be bound to inner elements and their data (as I said in my comment).

Whenever you set the content of an element as HTML string, you are creating new elements.

It might be better to recursively apply this function to every text node only. Something like:

$.fn.highlight = function(word) {
    var pattern = new RegExp(word, 'g'),
        repl = '<span class="high">' + word + '</span>';

    this.each(function() {
        $(this).contents().each(function() {
            if(this.nodeType === 3 && pattern.test(this.nodeValue)) {
                $(this).replaceWith(this.nodeValue.replace(pattern, repl));
            }
            else if(!$(this).hasClass('high')) {
                $(this).highlight(word);
            }
        });
    });
    return this;
};

DEMO

It could very well be that this is not very efficient though.

like image 119
Felix Kling Avatar answered Nov 16 '22 00:11

Felix Kling


To emulate Ctrl-F (which I assume is what you're doing), you can use window.find for Firefox, Chrome, and Safari and TextRange.findText for IE.

You should use a feature detect to choose which method you use:

function highlightText(str) {
    if (window.find)
        window.find(str);
    else if (window.TextRange && window.TextRange.prototype.findText) {
        var bodyRange = document.body.createTextRange();
        bodyRange.findText(str);
        bodyRange.select();
    }
}

Then, after you the text is selected, you can style the selection with CSS using the ::selection selector.

Edit: To search within a certain DOM object, you could use a roundabout method: use window.find and see whether the selection is in a certain element. (Perhaps say s = window.getSelection().anchorNode and compare s.parentNode == obj, s.parentNode.parentNode == obj, etc.). If it's not in the correct element, repeat the process. IE is a lot easier: instead of document.body.createTextRange(), you can use obj.createTextRange().

like image 2
Casey Chu Avatar answered Nov 16 '22 01:11

Casey Chu


$("body > *").each(function (index, element) {

  var parts = $(element).text().split("needle");
  if (parts.length > 1)
    $(element).html(parts.join('<span class="highlight">needle</span>'));
});

jsbin demo

at this point it's evolving to be more and more like Felix's, so I think he's got the winner


original:

If you're doing this in javascript, you already have a handy parsed version of the web page in the DOM.

// gives "user"
alert(document.getElementById('user').innerHTML);

or with jQuery you can do lots of nice shortcuts:

alert($('#user').html()); // same as above

$("a").each(function (index, element) {
    alert(element.innerHTML); // shows label text of every link in page
});
like image 1
Brad Mace Avatar answered Nov 15 '22 23:11

Brad Mace