Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Regular Expressions with jQuery Contains Regex Extension

I'm using an extension for jQuery "contains", shown below:

$.extend($.expr[':'],{
    containsExact: function(a,i,m){
        return $.trim(a.innerHTML.toLowerCase()) === m[3].toLowerCase();
    },
    containsExactCase: function(a,i,m){
        return $.trim(a.innerHTML) === m[3];
    },
    containsRegex: function(a,i,m){
        var regreg =  /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})$/,
        reg = regreg.exec(m[3]);
        return RegExp(reg[1], reg[2]).test($.trim(a.innerHTML));
    }
});

I have a table with certain cells that I'm trying to format conditionally, so I'm using the extension in a td selector, with the containsRegex function. The problem that I'm running into is that many of the regular expressions that I'm trying to use (which I've tested out on javascript regex testers like this and they've worked) do not work with this function. These are the various strings that I'd like to match:

Note that a "x" could be a x,t,f or v and an "X" could be an X,T,F or V. Lastly an "(mb)" could be any two lower case letters a-z in parenthesis.

-, (mb), x*, x*(mb), x, x(mb), X*, X*(mb), X

And here is the code with several of the regex statements that I'm using:

 $("td:containsExact('-')").addClass("0 queue"); // -
 $("td:containsRegex('/[^xtfv*]\([a-z]{2}\)/g')").addClass("1 active"); // (mb)
 $("td:containsRegex('/\b[xtfv]\*(?!\()/g')").addClass("2 queue review"); // x*
 $("td:containsRegex('/\b[xtfv]\*(?:\([a-z]{2}\))/g')").addClass("3 active review"); // x*(mb)
 $("td:containsRegEx('/\b[xtfv](?![*\(])/g')").addClass("4 queue");  // x
 $("td:containsRegEx('/\b[xtfv](?:\([a-z]{2}\))/g')").addClass("5 active");  // x(mb)
 $("td:containsRegEx('/\b[XTFV]\*(?!\()/g')").addClass("6 queue review");  // X*
 $("td:containsRegEx('/\b[XTFV]\*(?:\([a-z]{2}\))/g')").addClass("7 active review");  // X*(mb)
 $("td:containsRegEx('/\b[XTFV](?![*\(])/g')").addClass("8 done");  // X

Most of these pass errors in Chrome. Does anyone have any pointers? Is the contains extension limited somehow?

Thanks in advance for your help!

like image 400
mbeasley Avatar asked Jan 18 '12 17:01

mbeasley


2 Answers

Ok, I think I got it... These are the changes I made:

  • The bottom five selectors have a capital "E" and should all be "containsRegex()"
  • I changed the containsRegex a tiny bit by adding a "reg" check in the return, to make it more sturdy:

    containsRegex: function(a,i,m){
      var regreg =  /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})$/,
       reg = regreg.exec(m[3]);
      return reg ? RegExp(reg[1], reg[2]).test($.trim(a.innerHTML)) : false;
    }
    
  • All escaped characters in the regex need to be double escaped ( i.e. \( needs to be \\( )

  • I removed all the single quotes to actually help me from being distracted

  • I removed the class name numbers. I know ID's shouldn't start with numbers and I'm pretty sure class names shouldn't start or only be a number either. Anyway, this led to some selectors adding the same regex (i.e. "x" and "-" look the same, as well as "x*(mb)" and "X*(mb)" with the css in the demo).

Anyway, I'll update my gist with this code and your demo:

/* jQuery selector to match exact text inside an element
*  :containsExact()     - case insensitive
*  :containsExactCase() - case sensitive
*  :containsRegex()     - set by user ( use: $(el).find(':containsRegex(/(red|blue|yellow)/gi)') )
*/
$.extend($.expr[':'],{
  containsExact: function(a,i,m){
    return $.trim(a.innerHTML.toLowerCase()) === m[3].toLowerCase();
  },
  containsExactCase: function(a,i,m){
    return $.trim(a.innerHTML) === m[3];
  },
  containsRegex: function(a,i,m){
    var regreg =  /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})$/,
    reg = regreg.exec(m[3]);
    return reg ? RegExp(reg[1], reg[2]).test($.trim(a.innerHTML)) : false;
  }
});

// -, (mb), x*, x*(mb), x, x(mb), X*, X*(mb), X

$("td:containsRegex(/^[xtfv]$/)").addClass("queue");  // x
$("td:containsRegex(/^[xtfv]\\*$/)").addClass("queue review"); // x*
$("td:containsRegex(/^\\([a-z]{2}\\)$/)").addClass("active"); // (mb)
$("td:containsRegex(/^[xtfv]\\([a-z]{2}\\)$/)").addClass("active");  // x(mb)
$("td:containsRegex(/^[xtfv]\\*\\([a-z]{2}\\)$/)").addClass("active review"); // x*(mb)

$("td:containsRegex(/^[XTFV]$/)").addClass("done");  // X
$("td:containsRegex(/^[XTFV]\\*$/)").addClass("queue review");  // X*
$("td:containsRegex(/^[XTFV]\\*\\([a-z]{2}\\)$/)").addClass("active review");  // X*(mb)

$("td:containsExact(-)").addClass("queue"); // -
like image 183
Mottie Avatar answered Oct 29 '22 17:10

Mottie


"td:containsRegex('/\b[xtfv]\*(?!\()/g')"

\b inside a string literal means backspace ("\b" === "\x08") whereas it means wordbreak in a regex. Try replacing all the \b with \\b.

You should also properly change \( to [(] since in JS, "foo\(bar\)" === "foo(bar)".

like image 22
Mike Samuel Avatar answered Oct 29 '22 16:10

Mike Samuel