如何提高JavaScript文本格式化程序的性能?

时间:2011-08-01 18:16:48

标签: javascript regex performance

我允许我的用户将带有“*”,“/”,“_”和“ - ”的单词换行,作为表示他们想要粗体,斜体,下划线或删除其文本的简写方式。不幸的是,当页面使用此标记填充文本时,我看到一个明显的(可接受的边界线)减速。

这是我为处理此任务而编写的JavaScript。你能否就我如何加快速度提供反馈?

function handleContentFormatting(content) {
    content = handleLineBreaks(content);

    var bold_object = {'regex': /\*(.|\n)+?\*/i, 'open': '<b>', 'close': '</b>'};
    var italic_object = {'regex': /\/(?!\D>|>)(.|\n)+?\//i, 'open': '<i>', 'close': '</i>'};
    var underline_object = {'regex': /\_(.|\n)+?\_/i, 'open': '<u>', 'close': '</u>'};
    var strikethrough_object = {'regex': /\-(.|\n)+?\-/i, 'open': '<del>', 'close': '</del>'};

    var format_objects = [bold_object, italic_object, underline_object, strikethrough_object];

    for( obj in format_objects ) {
        content = handleTextFormatIndicators(content, format_objects[obj]);
    }

    return content;
}

//@param obj --- an object with 3 properties:
//      1.) the regex to search with
//      2.) the opening HTML tag that will replace the opening format indicator
//      3.) the closing HTML tag that will replace the closing format indicator
function handleTextFormatIndicators(content, obj) {
    while(content.search(obj.regex) > -1) {
        var matches = content.match(obj.regex);
        if( matches && matches.length > 0) {
            var new_segment = obj.open + matches[0].slice(1,matches[0].length-1) + obj.close;
            content = content.replace(matches[0],new_segment);
        }
    }
    return content;
}

3 个答案:

答案 0 :(得分:1)

您的代码强制浏览器执行大量重复,浪费的工作。你应该采取的方法是:

  1. 制作一个正则表达式,它将所有“目标”正则表达式与另一个匹配您的特殊元字符的主要字符串匹配的正则表达式。
  2. 更改循环,以便执行以下操作:
    1. 从源字符串中抓取下一个匹配项。由于您更改正则表达式的方式,该匹配将是一系列非元字符,后跟您的匹配部分。
    2. 将非元字符和目标部分的替换附加到单独的字符串数组上。
  3. 在该过程结束时,可以连接单独的累加器数组并用于替换内容。
  4. 至于如何组合正则表达式,嗯,它在JavaScript中不是很漂亮,但它看起来像这样。首先,你需要一个零或更多“无趣”字符串的正则表达式。这应该是正则表达式中的第一个捕获组。接下来应该是您正在寻找的目标字符串的替代项。因此,一般形式是:

    var tokenizer = /(uninteresting pattern)?(?:(target 1)|(target 2)|(target 3)| ... )?/;
    

    当您将其与源字符串匹配时,您将返回包含以下内容的结果数组:

    result[0] - entire chunk of string (not used)
    result[1] - run of uninteresting characters
    result[2] - either an instance of target type 1, or null
    result[3] - either an instance of target type 2, or null
    ...
    

    因此,您可以通过检查哪些目标正则表达式非空来了解您看到的替换目标。 (请注意,在您的情况下,目标可以想象重叠;如果您打算使用它,那么您将不得不将其视为我怀疑的完整解析问题。)

答案 1 :(得分:1)

  1. 使用标记/ig更改正则表达式并删除while循环。

  2. 使用正常for循环更改for(obj in format_objects)循环,因为format_objects是一个数组。


  3. 更新

    好的,我花时间根据您的代码编写了一个更快速,更简化的解决方案:

    function handleContentFormatting(content) {
        content = handleLineBreaks(content);
    
        var bold_object = {'regex': /\*([^*]+)\*/ig, 'replace': '<b>$1</b>'},
            italic_object = {'regex': /\/(?!\D>|>)([^\/]+)\//ig, 'replace': '<i>$1</i>'},
            underline_object = {'regex': /\_([^_]+)\_/ig, 'replace': '<u>$1</u>'},
            strikethrough_object = {'regex': /\-([^-]+)\-/ig, 'replace': '<del>$1</del>'};
    
        var format_objects = [bold_object, italic_object, underline_object, strikethrough_object],
            i = 0, foObjSize = format_objects.length;
    
        for( i; i < foObjSize; i++ ) {
            content = handleTextFormatIndicators(content, format_objects[i]);
        }
    
        return content;
    }
    
    //@param obj --- an object with 2 properties:
    //      1.) the regex to search with
    //      2.) the replace string
    function handleTextFormatIndicators(content, obj) {
        return content.replace(obj.regex, obj.replace);
    }
    

    Here is a demo

    这适用于嵌套和/或不嵌套的格式边界。如果您愿意,可以完全省略函数handleTextFormatIndicators,并在handleContentFormatting内部进行内联替换。

答案 2 :(得分:1)

您可以执行以下操作:

function formatText(text){
    return text.replace(
        /\*([^*]*)\*|\/([^\/]*)\/|_([^_]*)_|-([^-]*)-/gi,
        function(m, tb, ti, tu, ts){
            if(typeof(tb) != 'undefined')
                return '<b>' + formatText(tb) + '</b>';
            if(typeof(ti) != 'undefined')
                return '<i>' + formatText(ti) + '</i>';
            if(typeof(tu) != 'undefined')
                return '<u>' + formatText(tu) + '</u>';
            if(typeof(ts) != 'undefined')
                return '<del>' + formatText(ts) + '</del>';
            return 'ERR('+m+')';
        }
    );
}

这适用于嵌套标签,但不会使用重叠标签,无论如何都是无效的。

http://jsfiddle.net/m5Rju/

的示例