3

我正在使用 JavaScript 中的正则表达式编写一个基本的词法分析器,我有两个正则表达式(一个用于单引号字符串,一个用于双引号字符串),我希望将它们组合成一个。这是我的两个正则表达式(出于测试目的,我添加了^and字符):$

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;

现在我尝试将它们组合成一个正则表达式,如下所示:

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

但是,当我测试输入时"Hello"World!",它返回true而不是false

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

我认为问题[^\1\\]在于除了匹配组\1(单引号或双引号 - 字符串的分隔符)和\\(反斜杠字符)之外的任何字符。

正则表达式正确过滤掉反斜杠并匹配分隔符,但它不会过滤掉字符串中的分隔符。任何帮助将不胜感激。请注意,我参考了 Crockford 的铁路图来编写正则表达式。

4

3 回答 3

7

您不能在字符类中引用匹配组:(['"])[^\1\\]。尝试这样的事情:

(['"])((?!\1|\\).|\\[bnfrt]|\\u[a-fA-F\d]{4}|\\\1)*\1

(你需要添加更多的转义,但你明白我的意思......)

快速解释:

(['"])             # 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
于 2012-04-27T19:10:41.317 回答
2

这也应该有效(原始正则表达式)。
如果速度是一个因素,这是'展开'方法,据说是这种东西最快的方法。

(['"])(?:(?!\\|\1).)*(?:\\(?:[\/bfnrt]|u[0-9A-F]{4}|\1)(?:(?!\\|\1).)*)*/1  

展开

(['"])            # 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).         # As many non-escape and non-quote chars as possible
    )*
)*

/1                # Captured quote
于 2012-04-27T19:25:01.753 回答
0

好吧,您总是可以通过在较小的正则表达式上使用交替运算符来创建一个更大的正则表达式

/(?:single-quoted-regex)|(?:double-quoted-regex)/

或明确:

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

最后,如果您想避免代码重复,您可以使用new Regex构造函数动态构建此正则表达式。

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' );
于 2012-04-27T18:45:45.520 回答