开发者

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.

=开发者_如何学C= 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.


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.


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().


$("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
});


I like regexes, but because tags can be nested, you will have to use a parser. I recommend http://simplehtmldom.sourceforge.net/ it is really powerful and easy to use. If you have wellformed xhtml you can also use SimpleXML from php.

edit: Didn't see the javascript tag.


Try this:

/[(<.+>)(^<)]*user[(^>)(<.*>)]/

It means:

Before the keyword, you can have as many <...> or non-<.

Samewise after it.

EDIT:

The correct one would be:

/((<.+>)|(^<))*user((^>)|(<.*>))*/


Here is what works, I tried it on your JS Bin:

var s = 'hey <a href="#user">user</a>, what are you doing?';
s = s.replace(/(<[^>]*)user([^<]>)/g,'$1NEVER_WRITE_THAT_ANYWHERE_ELSE$2');
s = s.replace(/user/g,'Mr Smith');
s = s.replace(/NEVER_WRITE_THAT_ANYWHERE_ELSE/g,'user');
document.body.innerHTML = s;

It may be a tiny little bit complicated, but it works!

Explanation:

  • You replace "user" that is in the tag (which is easy to find) with a random string of your choice that you must never use again... ever. A good use would be to replace it with its hashcode (md5, sha-1, ...)
  • Replace every remaining occurence of "user" with the text you want.
  • Replace back your unique string with "user".


this code will strip all tags from sting

var s = 'hey <a href="#user">user</a>, what are you doing?';
s = s.replace(/<[^<>]+>/g,'');
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜