Different Browsers Use Different Non-Matching Captured RegEx Pattern Values

Posted May 7, 2010 at 8:40 AM by Ben Nadel

Tags: Javascript / DHTML

Yesterday, Alec Perkins brought it to my attention that Chrome was passing in an undefined value for a non-matching, captured group in a regular expression (RegEx) replace function. This is a different behavior than Firefox, which passes in an empty string for non-matching, captured groups. I typically only test my Javascript in Firefox (yes, it's a bad habit); so, after hearing this, I wanted to test this feature in a few different browsers to see how they all behaved. The demo for the experiment is quite simple - I'm just matching a pattern than has an optional, but non-matched group:

  • <!DOCTYPE HTML>
  • <html>
  • <head>
  • <title>Javascript String Replace Data Types</title>
  • <script type="text/javascript">
  •  
  • // Create a string to test.
  • var test = "You are just too sexy!";
  •  
  • // Create a pattern to match a sub-string with an optional
  • // capturing group - "way" is not required.
  • var pattern = new RegExp( "((way )?too sexy)", "gi" );
  •  
  • // Loop over the matches, passing each set of captured groups
  • // to the given function. In this case, the second captured
  • // group will be the OPTIONAL part of the pattern.
  • test.replace(
  • pattern,
  • function( $0, $1, $2 ){
  •  
  • // Alert the TYPE of data type passed-in for the non-
  • // captured group value.
  • alert( typeof( $2 ) );
  •  
  • // Alert the boolean-cast of the group.
  • alert( !!$2 );
  •  
  • }
  • );
  •  
  • </script>
  • </head>
  • <body>
  • <!--- Left intentially blank. --->
  • </body>
  • </html>

Here, I am looking for the regular expression pattern:

"((way )?too sexy)"

In this pattern, the substring, "way ", is an optional, captured group and will, in fact, not be matched in our test string, "You are just too sexy!". In this scenario, we can then see how the different browsers pass in the second captured (but not matched) group.

I tested this in Firefox, Chrome, IE, and Safari and here is what we get:

Firefox:
string
false

Chrome:
undefined
false

Safari:
undefined
false

IE:
undefined
false

As it turns out, Firefox is the odd man out here, being the only browser that passes in an empty string for non-matching groups. All of the other browsers pass in "undefined" / null data types for non-matching groups. While this difference is strange, the upside is that both empty strings and undefined values are "falsey" values in Javascript and can be implicitly cast to False for control flow decisions. I know some people frown upon the use of truthy / falsey values as Conditions, but when different browsers pass in different falsey data types, this feature really helps us to simplify our control flow logic.

Note to self: be sure to test Javascript in at least two browsers!




Reader Comments

Jun 14, 2010 at 10:24 AM // reply »
172 Comments

This is a Firefox bug in the handling of nonparticipating capturing groups. The following (old) post of mine lists additional related browser bugs and other info: http://blog.stevenlevithan.com/archives/npcg-javascript


Jun 14, 2010 at 2:13 PM // reply »
11,314 Comments

@Steve,

Ahh, bug! Thanks for the link. I'll be checking out your regex know-how :)


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
seb
Jun 20, 2013 at 2:32 AM
Working With Inherited Collections In AngularJS
@mike, @ben, The best article about scope and prototypal prototypical inheritance in angularjs is http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical- ... read »
Jun 20, 2013 at 2:17 AM
ColdFusion NumberFormat() Exploration
Nice read thanks Ben, Is there a way to mask a negative number? Long story short in the finance sector when you go 'short' on a stock you want the price to fall this is a good thing because you are ... read »
Jun 20, 2013 at 1:09 AM
The Beauty Of The jQuery Each() Method
my html code : <html> <head> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="nss.js"> ... read »
Jun 19, 2013 at 11:31 PM
Directive Link, $observe, And $watch Functions Execute Inside An AngularJS Context
@Ben, bunch to learn indeed, but thats fun part : ) ... read »
Jun 19, 2013 at 10:41 PM
Referencing ColdFusion Query Columns In A Loop Using Both Array And Dot Notation
Burdock-roots Are you going fat day by day? You need to be good for your family and make some money too. So we bring for you a best product that helps you to be more energetic every day. You will b ... read »
Jun 19, 2013 at 9:52 PM
Working With Inherited Collections In AngularJS
I recognize the applicability of your solution, and how easy it makes to share data across multiple views or even "submodules" of rather simple application. But it seems to me that it creat ... read »
Jun 19, 2013 at 9:38 PM
Directive Link, $observe, And $watch Functions Execute Inside An AngularJS Context
@Alesei, Glad you like it. Even after working with AngularJS for months, I still get a bunch of unexpected, "$digest is already in progress". So hard to debug sometimes! ... read »
Jun 19, 2013 at 9:36 PM
Working With Inherited Collections In AngularJS
@Mike, The relationship of $scope values is definitely an interesting thing! But it's not simple - it really forces you to understand prototypal inheritance, which is not at all a simple topic! Gla ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools