Take the 2-minute tour ×

I'm writing a rudimentary lexer using regular expressions in JavaScript and I have two regular expressions (one for single quoted strings and one for double quoted strings) which I wish to combine into one. These are my two regular expressions (I added the ^ and $ characters for testing purposes):

var singleQuotedString = /^'(?:[^'\\]|\\'|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*'$/gi;
var doubleQuotedString = /^"(?:[^"\\]|\\"|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*"$/gi;

Now I tried to combine them into a single regular expression as follows:

var string = /^(["'])(?:[^\1\\]|\\\1|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*\1$/gi;

However when I test the input "Hello"World!" it returns true instead of false:

alert(string.test('"Hello"World!"')); //should return false as a double quoted string must escape double quote characters

I figured that the problem is in [^\1\\] which should match any character besides \1 (which is either a single or a double quote - the delimiter of the string) and \\ (which is the backslash character).

The regular expression correctly filters out backslashes and matches the delimiters, but it doesn't filter out the delimiter within the string. Any help will be greatly appreciated. Note that I referred to Crockford's railroad diagrams to write the regular expressions.

share|improve this question
add comment

3 Answers

up vote 4 down vote accepted

You can't refer to a matched group inside a character class: (['"])[^\1\\]. Try something like this instead:


(you'll need to add some more escapes, but you get my drift...)

A quick explanation:

(['"])             # match a single or double quote and store it in group 1
(                  # start group 2
  (?!\1|\\).       #   if group 1 or a backslash isn't ahead, match any non-line break char
  |                #   OR
  \\[bnfrt]        #   match an escape sequence
  |                #   OR
  \\u[a-fA-F\d]{4} #   match a Unicode escape
  |                #   OR
  \\\1             #   match an escaped quote
)*                 # close group 2 and repeat it zero or more times
\1                 # match whatever group 1 matched
share|improve this answer
I never knew you could do something like (?!\1|\\).. On MDN it says that 'x(?!y)' matches 'x' only if 'x' is not followed by 'y'. –  Aadit M Shah Apr 27 '12 at 19:26
@Aadit M Shah - Its a poor analogy. You are always at a position between characters in regular expressions, like a cursor. Assertions stand still and (?!) and (?=) always refer to whats to the right of the current position. Its immaterial what is to the left of it other than if it didn't match, you would not be at this assertion. –  sln Apr 27 '12 at 22:30
Makes sense. Perhaps the MDN page should be updated. –  Aadit M Shah Apr 27 '12 at 22:46
@Aadit M Shah - No need to tell Microsoft the errors of its ways, its a company that consumes technology (with docs). Just google 'x' only if 'x' is not followed by 'y' –  sln Apr 30 '12 at 0:49
@sin - MDN stands for Mozilla Developer Network. Not Microsoft Developer Network. That's MSDN. Mozilla is the pioneer in JavaScript technology. Which self respecting programmer would go to Microsoft for any purpose? –  Aadit M Shah Apr 30 '12 at 4:38
show 1 more comment

This should work too (raw regex).
If speed is a factor, this is the 'unrolled' method, said to be the fastest for this kind of thing.



(['"])            # Capture a quote
   (?!\\|\1).             # As many non-escape and non-quote chars as possible

    \\                     # escape plus,
        [\/bfnrt]          # /,b,f,n,r,t or u[a-9A-f]{4} or captured quote
      | u[0-9A-F]{4}
      | \1

/1                # Captured quote
share|improve this answer
add comment

Well, you can always just create a larger regex by just using the alternation operator on the smaller regexes


Or explicitly:

var string = /(?:^'(?:[^'\\]|\\'|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*'$)|(?:^"(?:[^"\\]|\\"|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*"$)/gi;

Finally, if you want to avoid the code duplication, you can build up this regex dynamically, using the new Regex constructor.

var quoted_string = function(delimiter){
    return ('^' + delimiter + '(?:[^' + delimiter + '\\]|\\' + delimiter + '|\\\\|\\\/|\\b|\\f|\\n|\\r|\\t|\\u[0-9A-F]{4})*' + delimiter + '$').replace(/\\/g, '\\\\');
    //in the general case you could consider using a regex excaping function to avoid backslash hell.

var string = new RegExp( '(?:' + quoted_string("'") + ')|(?:' + quoted_string('"') + ')' , 'gi' );
share|improve this answer
I though of that; and then I thought that there must be a better way to do it. =) –  Aadit M Shah Apr 27 '12 at 18:50
Would you happen to know why [^\1\\] doesn't work as expected? –  Aadit M Shah Apr 27 '12 at 18:53
@AaditMShah: I just don't think you can use backreferences inside the classes like that. In any case I wrote down a version that does not duplicate the regex, but now you have to decide if you think it is more readable or not ;) –  missingno Apr 27 '12 at 19:05
add comment

Your Answer


