Wrap character in String, excluding a Link tag with Javascript Regex

前端 未结 3 1244
天命终不由人
天命终不由人 2021-01-28 08:54

EDIT

heres what i have to do...

Imagine if i have a text with some html tags inside it (it is still a string):

var string = \'

Hello, my

相关标签:
3条回答
  • Does this solution matches your requirements?

    string = string.replace(/a(?![^<]*?>)/g, '<span class="ui-match">a</span>');
    

    A little help about (?![^<]*?>) (roughly : "some text not followed by >") :

    (?!...)   not followed by
    [^<]*     any char except "<", zero or more times
    ?>        until next ">"
    

    Wrapped inside a function :

    function replace(html, text, replacement) {
        // RegExp.escape : http://stackoverflow.com/q/3561493/1636522
        var re = new RegExp('(' + RegExp.escape(text) + ')(?![^<]*?>)', 'g');
        return html.replace(re, replacement);
    }
    
    var html = '<a class="azerty"> azerty &lt; azerty </a>';
    html = replace(html, 'azerty', '<b>$1</b>');
    // "<a class="azerty"> <b>azerty</b> &lt; <b>azerty</b> </a>"
    
    0 讨论(0)
  • 2021-01-28 09:42

    I would recommend you to split the problem into 2 smaller problems:

    1. grab text content of all tags.
    2. wrap chars with <span class="ui-match"></span>

    Using RegExp to parse HTML is a bad idea but in this case since you seem to control the input structure you might use it to simplify the logic.

    Using a single RegExp for it will be really hard, so it's also better to do 2 String#replace instead of one. A generic implementation would be like:

    function replaceHtmlContent(str, match, replaceFn) {
      // we use the "g" and "i" flags to make it replace all occurrences and ignore case
      var re = new RegExp(match, 'gi');
      // this RegExp will match any char sequence that doesn't contain "<" or ">"
      // and that is followed by a tag
      return str.replace(/([^<>]+)(?=<[^>]+>)/g, function(s, content){
        return content.replace(re, replaceFn);
      });
    }
    

    which could be abstracted as:

    function wrapMatch(src, match) {
      return replaceHtmlContent(src, match, function(str){
        return '<span class="ui-match">'+ str +'</span>';
      });
    }
    

    and used later like:

    var output = wrapMatch(input, 'a');
    

    which would give the expected result for the example input.

    DEMO: http://jsbin.com/ovUFEsas/4/edit

    0 讨论(0)
  • 2021-01-28 09:46

    For not using regex, it will be faster to work with DOM nodes:

    var div = document.createElement('div'),
        children;
    
    div.innerHTML = 'Hello, my name is mauricio, and i like <a href="#">Star Wars</a>';
    children = div.childNodes;
    
    for (var i = 0, len = children.length; i < len; i++) {
        console.log(children[i]);
        if (children[i].nodeType === 3) {
            children[i].nodeValue = children[i].nodeValue.replace(/a/g, 'R');
        }
    }
    
    console.log(div.innerHTML);
    

    N.B.: I used innerHTML property as an example way here, however it is not recommended to exploit it because of a rather low performance.

    DEMO: http://jsfiddle.net/N7rdW/


    UPDATE:

    As per your update, you should better use the approach from my answer for another question from HERE. The code is a bit more complicated but is rather fast (not keeping in mind innerHTML usage):

    var div = document.createElement('div');
    div.innerHTML = 'Hello, my name is mauricio, and i like <a href="#">Star Wars</a>';
    
    for (var i = 0, children = div.childNodes, len = children.length; i < len; i++) {
        var child = children[i];
        if (child.nodeType === 3 && child.nodeValue.indexOf('a') > -1) {
            var segments = child.nodeValue.split('a');
            for (var k = 0, lk = segments.length; k < lk; k++) {
                div.insertBefore(document.createTextNode(segments[k]), child);
                if (k < lk - 1) {
                    var span = document.createElement('span');
                    span.className = 'ui-match';
                    span.appendChild(document.createTextNode('R'));
                    div.insertBefore(span, child);
                }
            }
            div.removeChild(child);
        }
    }
    
    console.log(div.innerHTML);
    

    DEMO: http://jsfiddle.net/T4ZXA/6/

    0 讨论(0)
提交回复
热议问题