简体   繁体   中英

Elusive bug in regex and string substitution

I have written a simple javascript searcher for a page and am running into some problems with mismatches/false matches as well as potentially poor css class matching.

http://jsfiddle.net/C4q7T/

If I click on the first example 'code' (which filters down to one element) then on the 'styling' link, the 'code' high-lighting remains. Needless to say this is undesirable.

I think that the problem will happen in the filtering part of the code but it all looks quite good to me. Especially since I am grabbing the text of the title rather than the HTML of it and then adding in a new span.

function filter(searchTerm) {
    var searchPattern = new RegExp('(' + searchTerm + ')', 'ig');  // The brackets add a capture group

    entries.fadeOut(150, function () {
        noResults.hide();

        $('header', this).each(function () {
            $(this).parent().hide();

            // Clear results of previous search
            $('li', this).removeClass('searchMatchTag');

            // Check the title
            $('h1', this).each(function () {
                var textToCheck = $('a', this).text();
                if (textToCheck.match(searchPattern)) {
                    textToCheck = textToCheck.replace(searchPattern, '<span class="searchMatchTitle">$1</span>');  //capture group ($1) used so that the replacement matches the case and you don't get weird capitolisations
                    $('a', this).html(textToCheck);
                    $(this).closest('.workshopentry').show();
                }
            });

            // Check the tags
            $('li', this).each(function () {
                if ($(this).text().match(searchPattern)) {
                    $(this).addClass('searchMatchTag');
                    $(this).closest('.workshopentry').show();
                }
            });
        });

        if ($('.workshopentry[style*="block"]').length === 0) {
            noResults.show();
        }

        entries.fadeIn(150);
    });
}

Some other combinations make this happen but some other s do not, making it very hard for me to track down the cause for this particular problem.

You can't trust user input with regular expressions without doing proper quoting. Consider using a quote function like this:

var rePattern = searchTerm.replace(/[.?*+^$\[\]\\(){}|]/g, "\\$&"),
searchPattern = new RegExp('(' + rePattern + ')', 'ig');  // The brackets add a capture group

Edit

As mentioned in the comments, it's not clear why capturing parentheses are being used to perform the search; you can use $& as the replacement pattern. Of course, I would understand if you simplified the regular expression for this post :)

Generating searchPattern without escaping searchTerm could be a problem. A searchTerm of .* would match anything.

How about using var match = textToCheck.indexOf(searchTerm) >= 0 instead?

This will return the index of the first instance of the substring searchTerm in the text, otherwise, it will return -1.

Turn out I was missing a check to remove the previous matching tags.

var textToCheck = $('a', this).text();
if (textToCheck.match(searchPattern)) {
    //capture group ($1) used so that the replacement matches the case and you don't get weird capitolisations
    textToCheck = textToCheck.replace(searchPattern, '<span class="searchMatchTitle">$1</span>');
    $('a', this).html(textToCheck);
    $(this).closest('.workshopentry').show();
} else {
    $('a', this).html(textToCheck);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM