正则表达式跳过模式

问题

我需要用百分号(’%’)替换所有星号(’*’)。 应忽略方括号中的星号符号。

[Test] public void Replace_all_asterisks_outside_the_square_brackets() { var input = "Hel[*o], w*rld!"; var output = Regex.Replace(input, "What_pattern_should_be_there?", "%") Assert.AreEqual("Hel[*o], w%rld!", output)); } 

尝试使用前瞻:

 \*(?![^\[\]]*\]) 

这是一个更强大的解决方案,它可以更好地处理[]块,甚至可以转义\[字符:

 string text = @"h*H\[el[*o], w*rl\]d!"; string pattern = @" \\. # Match an escaped character. (to skip over it) | \[ # Match a character class (?:\\.|[^\]])* # which may also contain escaped characters (to skip over it) \] | (?\*) # Match `*` and add it to a group. "; text = Regex.Replace(text, pattern, match => match.Groups["Asterisk"].Success ? "%" : match.Value, RegexOptions.IgnorePatternWhitespace); 

如果您不关心转义字符,可以将其简化为:

 \[ # Skip a character class [^\]]* # until the first ']' \] | (?\*) 

可以在没有注释的情况下编写: @"\[[^\]]*\]|(?\*)"

要理解它的工作原理,我们需要了解Regex.Replace的工作原理:对于字符串中的每个位置,它都会尝试匹配正则表达式。 如果失败,则移动一个字符 。 如果成功,则移动整个比赛。
在这里,我们有[...]块的虚拟匹配,所以我们可以跳过我们不想替换的星号,并且只匹配孤独的星号。 该决定是在回调函数中进行的,该函数检查Asterisk是否匹配。

我无法想出一个纯粹的RegEx解决方案。 因此,我正在为您提供务实的解决方案。 我测试了它,它的工作原理:

 [Test] public void Replace_all_asterisks_outside_the_square_brackets() { var input = "H*]e*l[*o], w*rl[*d*o] [o*] [o*o]."; var actual = ReplaceAsterisksNotInSquareBrackets(input); var expected = "H%]e%l[*o], w%rl[*d*o] [o*] [o*o]."; Assert.AreEqual(expected, actual); } private static string ReplaceAsterisksNotInSquareBrackets(string s) { Regex rx = new Regex(@"(?<=\[[^\[\]]*)(?\*)(?=[^\[\]]*\])"); var matches = rx.Matches(s); s = s.Replace('*', '%'); foreach (Match match in matches) { s = s.Remove(match.Groups["asterisk"].Index, 1); s = s.Insert(match.Groups["asterisk"].Index, "*"); } return s; } 

EDITED

好的,这是我最后的尝试;)

使用负向lookbehind (?和负向前瞻(?!)

 var output = Regex.Replace(input, @"(? 

这也将评论中的测试传递给另一个答案"Hel*o], w*rld!"