7

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!

1
  • For reference: the error it passes is "Uncaught Syntax error, unrecognized expression: )/g')" on "x*" and "X*". It appropriately applies the class to "(mb)" but also applies those same classes for "x*(mb)"... The rest of the searches don't pass errors, but they also don't find matches. Commented Jan 18, 2012 at 18:54

2 Answers 2

5

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"); // -
Sign up to request clarification or add additional context in comments.

2 Comments

Oh man - that worked perfectly. I completely overlooked double escaping, which I know think I understand the logic behind. The Regex versus RegEx thing was kind of dumb for me to overlook, but I'm glad you caught it. And I appreciate changes to your contains extension. That's really a superb piece of code, so once again - thank you!
I've updated the gist that contains this code to work with jQuery 1.8+. Note because of the changes to the expr function, the :containsRegex() function now does require quotes inside the parentheses.
2
"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)".

1 Comment

Unfortunately, the only thing that helped was replacing the ( with [(] where it searches for "x*" and "X*" - but all that did was prevent the error mentioned in my original comment. Still, the only one that is triggering is "(mb)" and unfortunately that one is still applying the trigger for "x*(mb)" as well... Thanks though. All part of troubleshooting this I suppose.

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.