匹配所有但不引用字符串

时间:2011-12-04 13:27:49

标签: javascript regex

我希望匹配所有内容,但没有引用的字符串。

我可以将所有引用的字符串与此匹配:/(("([^"\\]|\\.)*")|('([^'\\]|\\.)*'))/ 所以我尝试匹配所有内容但没有带引号的字符串:/[^(("([^"\\]|\\.)*")|('([^'\\]|\\.)*'))]/但它不起作用。

我想只使用正则表达式,因为我想要替换它并希望在它之后获取引用的文本。

string.replace(regex, function(a, b, c) {
   // return after a lot of operations
});

引用字符串对我来说就是这样“坏字符串”或者'酷字符串'

所以,如果我输入:

he\'re is "watever o\"k" efre 'dder\'4rdr'?

它应输出以下匹配项:

["he\'re is ", " efre ", "?"]

而且我不想替换它们。

我知道我的问题非常困难但并非不可能!没有什么是不可能的。

由于

3 个答案:

答案 0 :(得分:9)

编辑:重写以涵盖更多边缘案例。

这可以做到,但有点复杂。

result = subject.match(/(?:(?=(?:(?:\\.|"(?:\\.|[^"\\])*"|[^\\'"])*'(?:\\.|"(?:\\.|[^"'\\])*"|[^\\'])*')*(?:\\.|"(?:\\.|[^"\\])*"|[^\\'])*$)(?=(?:(?:\\.|'(?:\\.|[^'\\])*'|[^\\'"])*"(?:\\.|'(?:\\.|[^'"\\])*'|[^\\"])*")*(?:\\.|'(?:\\.|[^'\\])*'|[^\\"])*$)(?:\\.|[^\\'"]))+/g);

将返回

, he said. 
, she replied. 
, he reminded her. 
, 

来自此字符串(为了清楚起见,添加了换行符并删除了引号):

"Hello", he said. "What's up, \"doc\"?", she replied. 
'I need a 12" crash cymbal', he reminded her. 
"2\" by 4 inches", 'Back\"\'slashes \\ are OK!'

说明:(有点令人难以置信)

打破正则表达式:

(?:
 (?=      # Assert even number of (relevant) single quotes, looking ahead:
  (?:
   (?:\\.|"(?:\\.|[^"\\])*"|[^\\'"])*
   '
   (?:\\.|"(?:\\.|[^"'\\])*"|[^\\'])*
   '
  )*
  (?:\\.|"(?:\\.|[^"\\])*"|[^\\'])*
  $
 )
 (?=      # Assert even number of (relevant) double quotes, looking ahead:
  (?:
   (?:\\.|'(?:\\.|[^'\\])*'|[^\\'"])*
   "
   (?:\\.|'(?:\\.|[^'"\\])*'|[^\\"])*
   "
  )*
  (?:\\.|'(?:\\.|[^'\\])*'|[^\\"])*
  $
 )
 (?:\\.|[^\\'"]) # Match text between quoted sections
)+

首先,您可以看到有两个相似的部分。这两个前瞻断言都确保前面的字符串中有偶数个单/双引号,而忽略了相反类型的转义引号和引号。我将用单引号部分显示它:

(?=                   # Assert that the following can be matched:
 (?:                  # Match this group:
  (?:                 #  Match either:
   \\.                #  an escaped character
  |                   #  or
   "(?:\\.|[^"\\])*"  #  a double-quoted string
  |                   #  or
   [^\\'"]            #  any character except backslashes or quotes
  )*                  # any number of times.
  '                   # Then match a single quote
  (?:\\.|"(?:\\.|[^"'\\])*"|[^\\'])*'   # Repeat once to ensure even number,
                      # (but don't allow single quotes within nested double-quoted strings)
 )*                   # Repeat any number of times including zero
 (?:\\.|"(?:\\.|[^"\\])*"|[^\\'])*      # Then match the same until...
 $                    # ... end of string.
)                     # End of lookahead assertion.

双引号部分的作用相同。

然后,在字符串中这两个断言成功的每个位置,正则表达式的下一部分实际上试图匹配某些东西:

(?:      # Match either
 \\.     # an escaped character
|        # or
 [^\\'"] # any character except backslash, single or double quote
)        # End of non-capturing group

整个事情重复一次或多次,尽可能多次。 /g修饰符确保我们在字符串中获得所有匹配项。

See it in action here on RegExr

答案 1 :(得分:1)

这是一个经过测试的功能,可以解决这个问题:

function getArrayOfNonQuotedSubstrings(text) {
    /*  Regex with three global alternatives to section the string:
          ('[^'\\]*(?:\\[\S\s][^'\\]*)*')  # $1: Single quoted string.
        | ("[^"\\]*(?:\\[\S\s][^"\\]*)*")  # $2: Double quoted string.
        | ([^'"\\]*(?:\\[\S\s][^'"\\]*)*)  # $3: Un-quoted string.
    */
    var re = /('[^'\\]*(?:\\[\S\s][^'\\]*)*')|("[^"\\]*(?:\\[\S\s][^"\\]*)*")|([^'"\\]*(?:\\[\S\s][^'"\\]*)*)/g;
    var a = [];                 // Empty array to receive the goods;
    text = text.replace(re,     // "Walk" the text chunk-by-chunk.
        function(m0, m1, m2, m3) {
            if (m3) a.push(m3); // Push non-quoted stuff into array.
            return m0;          // Return this chunk unchanged.
        });
    return a;
}

此解决方案使用带有替换回调函数的String.replace()方法逐段“遍历”字符串。正则表达式有三个全局替代品,每个部分一个; $ 1:单引号,$ 2:双引号,$ 3:非引用子串,每个非引用的块被推送到返回数组。它正确处理所有转义字符,包括转义引号,内部和外部引用字符串。单引号子串可以包含任意数量的双引号,反之亦然。非法孤立引号被删除,用于将未引用的部分划分为两个块。请注意,此解决方案不需要环视,只需要一次通过。它还实现了Friedl的“Unrolling-the-Loop”效率技术并且非常有效。

附加:以下是使用原始测试字符串测试函数的一些代码:

// The original test string (with necessary escapes):
var s = "he\\'re is \"watever o\\\"k\" efre 'dder\\'4rdr'?";
alert(s); // Show the test string without the extra backslashes.
console.log(getArrayOfNonQuotedSubstrings(s).toString());

答案 2 :(得分:-5)

你无法反转正则表达式。你所尝试的是从中创建一个角色类并反转它 - 但是为了做到这一点你必须逃避所有右括号“\]”。

编辑:我本来是

/(^|" |' ).+?($| "| ')/

这匹配引用字符串的开头或结尾之间的任何内容(非常简单:引号加空格)和字符串的结尾或引用字符串的开头(空白加引号)。当然,这不会处理任何不遵循方案/ ['"].*['"] /的转义序列或引用。有关更详细的表达,请参阅上面的答案: - )