1

I just learned that you can create custom filters for jquery very easily and put together a filter to use regular expression match function on text content or any attribute.

I prepend the attribute to be matched to a normal regex, I know this is strange, please don't be thrown by this, or think less of me for it.

The problem I am having is when there are brackets in the regex that is to be matched. Sometimes it is fine, sometimes it causes syntax error.

fine: :match(src/jquery.+\.(js)/i)') error: :match(src/jquery.+\.js()/i)')

Can anyone tell me the reason for this behavior from this code?

// create new jquery filter
jQuery.expr[':'].match = function(e,i,p) { // element, index, params

    // split params by custom format
    m = p[3].match(/^([a-z]*)(\/?)(.+)\2([a-z]*)$/)

    // set the attribute to be checked
    myAttr = m[1] ? m[1] : 'text'

    // define regex, including switches
    myRegExp = new RegExp(m[3],m[4]);

    // check for and return matched elements
    if(myAttr == 'text')
        return $(e).text().match(myRegExp)
    else
        return $(e).attr(myAttr) ? $(e).attr(myAttr).match(myRegExp) : false
};

// used like this
// :match(attr/regex/switches)
// or with default match (text) and case insensitivity switch (i):
// :match(/HeLlO WoRl/i)
// or in simplest form
// :match(RegexPattern)

// alert how many jquery plugins of the form jquery.something.js
alert($('script:match(src/jquery.+\.js/i)').length)

Due to the excellent answer I received to this question, I decided to re-work my filter into a plugin function called match. Does anyone have any comments of how to improve it? Will it work for all circumstances?

// will save as file called jquery.match.js
// will wrap with
// (function($){
$.fn.match = function(regex, attr){ // optional attr
    return this.filter(function(){
        var subject = attr ? $(this).attr(attr) : $(this).text()
        return subject && subject.match(regex) ? 1 : 0
    })
}
// and end with
// })

// used like this: $('body *').match(/some content/)
// or to match attributes like this: $('script').match(/jquery/i,'src')
2
  • just curious, does jQuery have documentation for this feature? I couldn't seem to find it. Commented Apr 7, 2011 at 4:02
  • I would expect to find it in the commented source, but I did not look. Commented Apr 7, 2011 at 8:44

1 Answer 1

1

Your code appears to be failing because of the extra parenthesis in the second regex. Since jQuery is parsing the expression before you can, and has no knowledge of your predefined format, it will see :match(src/jquery.+\.js()/i) as :match(src/jquery.+\.js() + /i). Note that the second parenthesis is being interpreted as a close to the match.

There might be a way to tell jQuery to accept escaped versions of that ) but I'm not sure how.

Alternatively

You can just use the jQuery filter function like so.

$('script').filter( function(){
    return $(this).attr("src").match( /jquery/i ); 
});

To achieve a similar level of generality like your plugin was providing, you can create a higher order function to do the job.

function createFilterFunction(regex, /*optional*/ attr){
    return function(){
        if( !attr ){
            return $(this).text().match(myRegex);
        }
        return $(this).attr(attr) ? $(this).attr(attr).match(regex) : false;
    };
}

Then you could use it like such:

var isJquery = createFilterFunction( /jquery.+\.js()/i, "src" );
alert( $('script').filter( isJquery ).length );

Side Note

When writing javascript, if you don't include var in front of your variables, they will "leak" into the global namespace. So, your variables m, myAttr, and myRegExp will all be visible to anyone who uses your script, and more importantly it will change their values of m, myAttr, and myRegExp if they exist. Declare them like var m = ... instead.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the pointer re global variables. I took your excellent answer, and re-worked it into a plugin. Could you look it over at the end of freshly edited question for me - I think it is fine, but thought you could check seeing as it started as your code :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.