正则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 JavaScript
和any 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式有三个分支:
-
\\"
匹配而忽略 -
"(?:\\"|[^"])*"
匹配并忽略 -
(\+)
匹配, 捕获和处理
请注意,在其他正则expression式中,我们可以更容易地做到这一点,但JS不支持它。
完整的正则expression式变成:
\\"|"(?:\\"|[^"])*"|(\+)
请参阅正则expression式演示和完整的脚本 。
参考
- 除了情况s1,s2,s3,如何匹配模式
- 除非…匹配模式
你可以分三步做。
- 使用正则expression式全局replace将所有string正文内容提取到一个边桌。
- 做你的逗号翻译
- 使用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没有在非转义引用对之外的引号。