优化正则表达式以过滤数千个HTML选择选项

时间:2012-11-26 00:45:17

标签: javascript jquery regex optimization diacritics

背景

我为HTML select元素开发了一个基于jQuery的shuttle widget,因为我找不到一个编码最少的元素,并提供了一个补偿diacritics的正则表达式过滤器。

问题

当向select添加几千个条目时,正则表达式过滤器会慢速爬行。您可以按如下方式查看问题:

  1. 浏览至:http://jsfiddle.net/U8Xre/2/
  2. 单击结果面板中的输入字段。
  3. 输入任何正则表达式(例如^a.*ai)。
  4. 代码

    我相信罪魁祸首潜伏在这里:

    var options = $src.empty().scrollTop( 0 ).data( "options" );
    var search = $.trim( $input.val() );
    var regex = new RegExp( search, 'gi' );
    var len = options.length;
    var $html = $(document.createElement( 'option' ));
    for( var i = 0; i < len; i++ ) {
      var o = options[ i ];
      if( o.text.dediacritics().match( regex ) !== null ) {
        $src.append( $html.clone().text( o.text ).val( o.value ) );
      }
    }
    $src.css( 'width', $input.width() + 4 );
    

    其中$src是来源$('#select')String.prototype.dediacritics定义为小提琴。上面的代码适用于每一个按键。还有一个相关的片段:

    // Create a copy of the source options to use when matching the regex.
    var $options = [];
    $src.find( "option" ).each( function() {
      $options.push( { value: $(this).val(), text: $(this).text() } );
    });
    $src.data( "options", $options );
    

    这会从源列表中复制选项,但只运行一次。 (这会在传递选项时产生重复错误,但将上述代码添加到input事件处理程序中会使缓冲区更慢。)

    问题

    如何使代码几乎实时地在最多5,000个单词的列表上执行正则表达式过滤?

    谢谢!

3 个答案:

答案 0 :(得分:1)

我建议你

  • 创建一个包含所有选项名称列表的多行字符串,每个选项名称都在一个单独的行中
  • 将regex应用于此多行字符串,以通过删除不匹配的行来过滤其内容
  • 使用匹配的行更新html作为select元素的选项

答案 1 :(得分:1)

我猜更艰难的工作是重复调用dediacritics()(有许多正则表达式替换)而不是搜索(尽管我没有进行任何分析)。因此,您应该缓存这些去变质字符串并仅通过它们进行搜索。顺便说一下,test通常比match快。

此外,您应该避免尽可能多的DOM操作 - 在清空并重新附加整个选项列表onkeypress时,您有很多这样的操作。

// once:
var options = [],
    src = $src[0]; // or whatever to get the DOM element
$.each( src.options, function() {
    options.push( { el: this, text: $(this).text().dediacritics(), hidden:false } );
});
// you might put it on the element via .data(), but need not

// onkeypress:
var regex = new RegExp( $.trim($input.val()), 'i' );
var curEl = src.firstChild;
for (var i=0; i<options.length; i++) {
    var option = options[i];
    if (regex.test( option.text )) {
        if (option.hidden)
            src.insertBefore(option.el, curEl);
        curEl = option.el.nextSibling;
        option.hidden = false;
    } else {
        if (!option.hidden) {
            curEl = option.el.nextSibling;
            src.removeChild(option.el);
        }
        option.hidden = true;
    }
}

Demo:这非常快(“实时”),但在调用options 5000次时,您可以感受到构建dediacritics()数组所需的时间。

答案 2 :(得分:1)

一个小评论,如果你没有使用正则表达式匹配的结果,那么你应该使用正则表达式测试:

  if( o.text.dediacritics().match( regex ) !== null ) {

使用测试:

  if( regex.test(o.text.dediacritics()) ) {