正则expression式的替代方法:匹配不在引号内的所有实例

从这个Q / A ,我推断匹配一个给定的正则expression式的所有实例不在引号内,是不可能的。 也就是说,它不能匹配转义的引号(例如: "this whole \"match\" should be taken" )。 如果有办法做到这一点,我不知道,这将解决我的问题。

如果没有,但是,我想知道是否有任何有效的替代方法可以在JavaScript中使用。 我已经想了一下,但不能提供任何优雅的解决scheme,即使不是全部情况下也能运行。

具体来说,我只需要使用.split()和.replace()方法的替代方法,但如果它可以更普遍化,那将是最好的。

例如:
inputstring为:
+bar+baz"not+or\"+or+\"this+"foo+bar+
用#replace+,不要在引号内,将返回:
#bar#baz"not+or\"+or+\"this+"foo#bar#

实际上,你可以匹配任何string中不包含引号的正则expression式的所有实例,每个开启引号再次closures。 就像你上面的例子一样,你要匹配\+

这里关键的观察是,如果在它之后有一个偶数的引号,那么一个单词在引号之外。 这可以build模为一个预见性的断言:

 \+(?=([^"]*"[^"]*")*[^"]*$) 

现在,你不想计算逃脱的报价。 这变得更复杂一点。 取而代之的是[^"]* ,它需要考虑反斜杠,并使用[^"\\]* 。 在到达反斜线或引号之后,如果遇到反斜杠,则需要忽略下一个字符,否则前进到下一个未转义的引用。 看起来像(\\.|"([^"\\]*\\.)*[^"\\]*") 。 结合起来,你到达

 \+(?=([^"\\]*(\\.|"([^"\\]*\\.)*[^"\\]*"))*[^"]*$) 

我承认这有点神秘。 =)

Azmisov,复活这个问题,因为你说你正在寻找any efficient alternative that could be used in JavaScriptany elegant solutions that would work in most, if not all, cases

碰巧有一个简单的,一般的解决scheme,没有提到。

与替代scheme相比,这个解决scheme的正则expression式非常简单:

 "[^"]+"|(\+) 

这个想法是,我们匹配,但忽略引号内的任何内容来中和该内容(在replace的左侧)。 在右侧,我们捕获所有未被中和的+到组1中,replacefunction检查组1.这里是完整的工作代码:

 <script> var subject = '+bar+baz"not+these+"foo+bar+'; var regex = /"[^"]+"|(\+)/g; replaced = subject.replace(regex, function(m, group1) { if (!group1) return m; else return "#"; }); document.write(replaced); 

在线演示

您可以使用相同的原则进行匹配或拆分。 请参阅参考资料中的问题和文章,这也将指出您的代码示例。

希望这给你一个非常普遍的方式来做这个不同的想法。 🙂

那么空string呢?

以上是展示该技术的一般答案。 它可以根据你的确切需要调整。 如果担心文本可能包含空string,只需将string捕获expression式中的量词从+更改为*

 "[^"]*"|(\+) 

看演示 。

怎么逃脱行情?

再次,以上是展示该技术的一般答案。 不仅可以将“ 忽略这个匹配 ”的正则expression式细化到您的需要,您可以添加多个expression式来忽略。 例如,如果您想确保转义引号被充分忽略,您可以先在其他两个引脚之前加上\\"|以匹配(和忽略)转义的双引号。

接下来,在捕获双引号string内容的部分"[^"]*"中,可以添加一个交替,以确保在双引号"有机会变成closures标记之前匹配" "(?:\\"|[^"])*"

结果expression式有三个分支:

  1. \\"匹配而忽略
  2. "(?:\\"|[^"])*"匹配并忽略
  3. (\+)匹配, 捕获和处理

请注意,在其他正则expression式中,我们可以更容易地做到这一点,但JS不支持它。

完整的正则expression式变成:

 \\"|"(?:\\"|[^"])*"|(\+) 

请参阅正则expression式演示和完整的脚本 。

参考

  1. 除了情况s1,s2,s3,如何匹配模式
  2. 除非…匹配模式

你可以分三步做。

  1. 使用正则expression式全局replace将所有string正文内容提取到一个边桌。
  2. 做你的逗号翻译
  3. 使用regex全局replace来交换string主体

下面的代码

 // Step 1 var sideTable = []; myString = myString.replace( /"(?:[^"\\]|\\.)*"/g, function (_) { var index = sideTable.length; sideTable[index] = _; return '"' + index + '"'; }); // Step 2, replace commas with newlines myString = myString.replace(/,/g, "\n"); // Step 3, swap the string bodies back myString = myString.replace(/"(\d+)"/g, function (_, index) { return sideTable[index]; }); 

如果你设置后运行

 myString = '{:a "ab,cd, efg", :b "ab,def, egf,", :c "Conjecture"}'; 

你应该得到

 {:a "ab,cd, efg" :b "ab,def, egf," :c "Conjecture"} 

这是有效的,因为在步骤1之后,

 myString = '{:a "0", :b "1", :c "2"}' sideTable = ["ab,cd, efg", "ab,def, egf,", "Conjecture"]; 

所以myString中的唯一逗号是外部string。 步骤2,然后转动

 myString = '{:a "0"\n :b "1"\n :c "2"}' 

最后我们把只包含数字的stringreplace成原来的内容。

虽然zx81的答案似乎是最好的performance和干净的一个,它needes这些修复正确地抓住逃脱的报价:

 var subject = '+bar+baz"not+or\\"+or+\\"this+"foo+bar+'; 

 var regex = /"(?:[^"\\]|\\.)*"|(\+)/g; 

另外已经提到“group1 === undefined”或“!group1”。 特别是2.考虑到原来问题中的所有问题,似乎很重要。

应该提到的是,这个方法隐含地要求string没有在非转义引用对之外的引号。