我有以下简单的测试,我试图获取 Regex 模式,以便它在没有“.exe”后缀的情况下猛拉可执行文件名称。
看来我的非捕获组设置(?:\\.exe)不起作用,或者我误解了它的工作原理。
无论regex101和regexstorm.net显示了同样的结果和前确认“(?:\。exe文件)”是一个非获取匹配。
关于我做错了什么的任何想法?
// test variable for what i would otherwise acquire from Environment.CommandLine
var testEcl = "\"D:\\src\\repos\\myprj\\bin\\Debug\\MyApp.exe\" /?"
var asmName = Regex.Match(testEcl, @"[^\\]+(?:\.exe)", RegexOptions.IgnoreCase).Value;
// expecting "MyApp" but I get "MyApp.exe"
Run Code Online (Sandbox Code Playgroud)
我已经能够通过使用定义了组名的匹配模式来提取我想要的值,如下所示,但想了解为什么非捕获组设置方法没有按我预期的方式工作。
// test variable for what i would otherwise acquire from Environment.CommandLine
var testEcl = "\"D:\\src\\repos\\myprj\\bin\\Debug\\MyApp.exe\" /?"
var asmName = Regex.Match(Environment.CommandLine, @"(?<fname>[^\\]+)(?<ext>\.exe)",
RegexOptions.IgnoreCase).Groups["fname"].Value;
// get the desired "MyApp" result
Run Code Online (Sandbox Code Playgroud)
/eoq
一个(?:...)是一个非捕获组比赛,仍然会消耗文本。这意味着该组匹配的文本部分仍会添加到整体匹配值中。
一般来说,如果你想匹配一些东西而不是消费,你需要使用lookarounds。因此,如果您需要匹配特定字符串后跟的内容,请使用正向前瞻,(?=...)构造:
some_pattern(?=specific string) // if specific string comes immmediately after pattern
some_pattern(?=.*specific string) // if specific string comes anywhere after pattern
Run Code Online (Sandbox Code Playgroud)
如果您之前需要匹配但“从匹配中排除”某些特定文本,请使用积极的lookbehind:
(?<=specific string)some_pattern // if specific string comes immmediately before pattern
(?<=specific string.*?)some_pattern // if specific string comes anywhere before pattern
Run Code Online (Sandbox Code Playgroud)
注意,.*?或者.*-也就是说,用图案*,+,?,{2,}甚至{1,3}量词-在回顾后发模式并不总是由正则表达式引擎的支持,然而,C#.NET正则表达式引擎幸运支持它们。它们还得到 Python PyPiregex模块、Vim、JGSoft 软件以及现在符合 ECMAScript 2018 的 JavaScript 环境的支持。
在这种情况下,您可能会捕获您需要获取的内容,而无需捕获即可匹配上下文:
var testEcl = "\"D:\\src\\repos\\myprj\\bin\\Debug\\MyApp.exe\" /?";
var asmName = string.Empty;
var m = Regex.Match(testEcl, @"([^\\]+)\.exe", RegexOptions.IgnoreCase);
if (m.Success)
{
asmName = m.Groups[1].Value;
}
Console.WriteLine(asmName);
Run Code Online (Sandbox Code Playgroud)
参见C# 演示
细节
([^\\]+)-捕获组 1:一个或多个字符,而不是\\. - 一个文字点exe- 文字exe子串。因为我们只对捕获组 #1 的内容感兴趣,所以我们抓取m.Groups[1].Value,而不是整个m.Value(包含.exe)。