正则表达式匹配引号外的所有实例

这个问答中,我推断出在引号中匹配给定正则表达式 没有的所有实例是不可能的。也就是说,它不能匹配转义引号(例如: "this whole \"match\" should be taken")。如果有一种我不知道的方法,就能解决我的问题。

但是,如果没有,我想知道是否有任何有效的替代方法可以在 JavaScript 中使用。我已经想了一会儿,但不能提出任何优雅的解决方案,这将在大多数情况下,如果不是所有的情况下工作。

具体来说,我只是需要另一个选择。Split ()和。方法,但是如果它可以更通用化,那将是最好的。

例如:
输入字符串: < br/> +bar+baz"not+or\"+or+\"this+"foo+bar+ < br/> 用 # 替换 + ,而不是在引号内,将返回: < br/> #bar#baz"not+or\"+or+\"this+"foo#bar#

52210 次浏览

你可以分三步来做。

  1. 使用 regex 全局替换将所有字符串体内容提取到一个副表中。
  2. 做你的逗号翻译
  3. 使用 regex 全局替换将字符串主体交换回来

下面的代码

// 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"}

这很有效,因为在第一步之后,

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

所以 myString 中唯一的逗号是字符串之外的。步骤2,然后将逗号转换为换行符:

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

最后,我们将只包含数字的字符串替换为其原始内容。

实际上,您可以匹配任何字符串的不在引号内的正则表达式的所有实例,其中每个开始引号再次关闭。例如,在上面的示例中,您希望匹配 \+

这里的关键观察是,如果一个单词后面有偶数个引号,那么这个单词就在引号之外。这可以被建模为一个前瞻性断言:

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

现在,请不要计算转义引语。事情变得有点复杂了。您需要考虑使用反斜杠并使用 [^"\\]*,而不是前进到下一个引号的 [^"]*。到达反斜杠或引号之后,如果遇到反斜杠,则需要忽略下一个字符,否则将前进到下一个未转义引号。看起来像 (\\.|"([^"\\]*\\.)*[^"\\]*")。加起来,你就到了

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

我承认这是一个 一点点神秘的。 =)

阿兹米索夫,重提这个问题是因为你说你在找 any efficient alternative that could be used in JavaScriptany elegant solutions that would work in most, if not all, cases

碰巧有一个简单的,通用的解决方案,没有被提及。

与替代方案相比,这个解决方案的正则表达式简单得惊人:

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

其思想是,我们匹配但忽略引号中的任何内容,以中和该内容(在左侧的交替)。在右侧,我们捕获所有未中和到第1组的 +,并且替换函数检查第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);

在线演示

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

希望这给你一个不同的想法,一个非常一般的方法来做到这一点。 :)

那空字符串呢?

以上是展示该技术的一般答案。它可以根据您的具体需要进行调整。如果您担心文本可能包含空字符串,只需将字符串捕获表达式中的量词从 +更改为 *:

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

参见 小样

逃逸语录怎么样?

同样,以上是展示该技术的一般答案。“ 无视这场比赛”正则表达式不仅可以根据您的需要进行改进,还可以添加多个表达式来忽略。例如,如果希望确保充分忽略转义引号,可以首先在其他两个引号之前添加一个交替 \\"|,以匹配(并忽略)散列转义双引号。

接下来,在捕获双引号字符串内容的 "[^"]*"部分中,您可以添加一个替换,以确保在转义双引号被匹配之前,它们的 "有机会变成一个结束哨兵,将其变成 "(?:\\"|[^"])*"

得到的表达式有三个分支:

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

请注意,在其他正则表达式中,我们可以更容易地使用 lookbehind 完成这项工作,但是 JS 不支持它。

完整的正则表达式变成:

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

参见 正则表达式演示完整的剧本

参考

  1. 除了在 s1,s2,s3的情况下,如何匹配模式
  2. 如何匹配模式,除非..。

虽然 zx81给出的答案看起来是性能最好、最简洁的,但是它需要这些修复来正确捕捉转义引号:

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

还有

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

还有已经提到的“ group1 = = 未定义”或“ ! group1”。 尤其是2。似乎重要的是,实际上要考虑到在原来的问题中所问的一切。

应该提到的是,这个方法隐式地要求字符串在非转义引号对之外没有转义引号。