C# 正则表达式,包括结果中应该是非捕获组的内容

C# 正则表达式,包括结果中应该是非捕获组的内容,c#,.net,regex,C#,.net,Regex,下面是一个简单的测试,我试图获取Regex模式,这样它就可以在没有“.exe”后缀的情况下拖动可执行文件名。 似乎我的非捕获组设置(?:\\.exe)不起作用,或者我误解了它的工作原理。 和都显示相同的结果,前者确认“(?:\.exe)”是非捕获匹配。 有没有想过我做错了什么 // test variable for what i would otherwise acquire from Environment.CommandLine var testEcl = "\"D:\\src\\repo

下面是一个简单的测试,我试图获取Regex模式,这样它就可以在没有“.exe”后缀的情况下拖动可执行文件名。

似乎我的非捕获组设置
(?:\\.exe)
不起作用,或者我误解了它的工作原理。

和都显示相同的结果,前者确认“(?:\.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"
我已经能够通过使用定义了组名的匹配模式来提取我想要的值,如下所示,但我想了解为什么非捕获组设置方法没有按我预期的方式工作

// 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
//测试变量,否则我将从Environment.CommandLine获取
var testEcl=“\”D:\\src\\repos\\myprj\\bin\\Debug\\MyApp.exe\/?”
var asmName=Regex.Match(Environment.CommandLine,@“(?[^\\]+)(?\.exe)”,
RegexOptions.IgnoreCase)。组[“fname”]。值;
//获取所需的“MyApp”结果

/eoq将匹配未捕获组,但不会捕获它,因此如果您想要未捕获的部分,则应访问捕获组,而不是整个匹配

您可以在中访问组

var asmName = Regex.Match(testEcl, @"([^\\]+)(?:\.exe)", RegexOptions.IgnoreCase);
asmName.Groups[1].Value
正则表达式的演示可以找到

A
(?:…)
是一个非捕获组,它匹配并仍然使用文本。这意味着该组匹配的文本部分仍然添加到整体匹配值中

一般来说,如果你想匹配某样东西而不是消费,你需要使用lookarounds。因此,如果您需要匹配后跟特定字符串的内容,请使用正向前瞻,
(?=…)
构造:

some_pattern(?=specific string) // if specific string comes immmediately after pattern
some_pattern(?=.*specific string) // if specific string comes anywhere after pattern
如果之前需要匹配但“从匹配中排除”某些特定文本,请使用正向查找:

详细信息

  • ([^\\]+)
    -捕获组1:除
    \
  • \。
    -文字点
  • exe
    -文本
    exe
    子字符串
因为我们只对捕获组1内容感兴趣,所以我们获取
m.Groups[1].Value
,而不是整个
m.Value
(包含
.exe
)。

您使用的是。重点是这里的词组;该组不捕获
.exe
,但通常正则表达式仍然捕获

您可能希望使用,它只是断言字符串必须满足匹配有效的条件,尽管没有捕获该条件

换句话说,您希望在组开始时使用
(?=
),而不是
(?:

前者仅在枚举时使用;在您的示例中,您只是在使用,因此普通组
(\.exe)
和非捕获组
(?:\.exe)
之间没有区别

为了看到区别,请考虑这个测试程序:

static void Main(string[] args)
{
    var positiveInput = "\"D:\\src\\repos\\myprj\\bin\\Debug\\MyApp.exe\" /?";
    Test(positiveInput, @"[^\\]+(\.exe)");
    Test(positiveInput, @"[^\\]+(?:\.exe)");
    Test(positiveInput, @"[^\\]+(?=\.exe)");

    var negativeInput = "\"D:\\src\\repos\\myprj\\bin\\Debug\\MyApp.dll\" /?";
    Test(negativeInput, @"[^\\]+(?=\.exe)");
}

static void Test(String input, String pattern)
{
    Console.WriteLine($"Input: {input}");
    Console.WriteLine($"Regex pattern: {pattern}");

    var match = Regex.Match(input, pattern, RegexOptions.IgnoreCase);

    if (match.Success)
    {
        Console.WriteLine("Matched: " + match.Value);
        for (int i = 0; i < match.Groups.Count; i++)
        {
            Console.WriteLine($"Groups[{i}]: {match.Groups[i]}");
        }
    }
    else
    {
        Console.WriteLine("No match.");
    }
    Console.WriteLine("---");
}
第一个正则表达式(
@“[^\\]+(\.exe)”
)具有与普通组相同的
\.exe。
当我们枚举Groups属性时,我们看到
.exe
确实是在输入中捕获的一个组。 (请注意,整个正则表达式本身就是一个组,因此
Groups[0]
等于
Value

第二个正则表达式(
@“[^\\]+(?:\.exe)”
)就是您的问题中提供的。 与上一个场景相比,唯一的区别是Groups属性不包含
.exe
作为其条目之一

第三个正则表达式(
@“[^\\]+(?=\.exe)”
)是我建议您使用的。
现在,输入的
.exe
部分根本不会被正则表达式捕获,但是正则表达式将不会匹配字符串,除非它以
.exe
结尾,如第四个场景所示。

var testEcl=“\”D:\\src\\repos\\myprj\\bin\\Debug\\MyApp.exe\”获取
MyApp
您可以使用
Path.GetFileName
作为
string directory=Path.GetFileName(testEcl);
@Ashik,感谢您基于非正则表达式的建议。已尝试的Path.GetFileName()和.GetFileNameWithoutExtension()都会抛出System.ArgumentException“路径中的非法字符”。结果。您的路径包括
在开头和结尾。请尝试删除引号,谢谢您的响应。我正在查找匹配的捕获部分,而不是通过
(?:)
设置表示为非捕获组的部分。当我尝试上述检索.Groups[1]时,值会生成”“空字符串和.Groups[0].Value与我仅拉动.Value和Groups.Count时得到的结果相同。感谢您,现在它可以工作了。根据其他响应,我甚至不需要(?:)非捕获设置,在这种情况下,无论是否有,都不会影响未命名捕获组()设置将所需匹配放入组[1]。Value
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);
static void Main(string[] args)
{
    var positiveInput = "\"D:\\src\\repos\\myprj\\bin\\Debug\\MyApp.exe\" /?";
    Test(positiveInput, @"[^\\]+(\.exe)");
    Test(positiveInput, @"[^\\]+(?:\.exe)");
    Test(positiveInput, @"[^\\]+(?=\.exe)");

    var negativeInput = "\"D:\\src\\repos\\myprj\\bin\\Debug\\MyApp.dll\" /?";
    Test(negativeInput, @"[^\\]+(?=\.exe)");
}

static void Test(String input, String pattern)
{
    Console.WriteLine($"Input: {input}");
    Console.WriteLine($"Regex pattern: {pattern}");

    var match = Regex.Match(input, pattern, RegexOptions.IgnoreCase);

    if (match.Success)
    {
        Console.WriteLine("Matched: " + match.Value);
        for (int i = 0; i < match.Groups.Count; i++)
        {
            Console.WriteLine($"Groups[{i}]: {match.Groups[i]}");
        }
    }
    else
    {
        Console.WriteLine("No match.");
    }
    Console.WriteLine("---");
}
Input: "D:\src\repos\myprj\bin\Debug\MyApp.exe" /?
Regex pattern: [^\\]+(\.exe)
Matched: MyApp.exe
Groups[0]: MyApp.exe
Groups[1]: .exe
---
Input: "D:\src\repos\myprj\bin\Debug\MyApp.exe" /?
Regex pattern: [^\\]+(?:\.exe)
Matched: MyApp.exe
Groups[0]: MyApp.exe
---
Input: "D:\src\repos\myprj\bin\Debug\MyApp.exe" /?
Regex pattern: [^\\]+(?=\.exe)
Matched: MyApp
Groups[0]: MyApp
---
Input: "D:\src\repos\myprj\bin\Debug\MyApp.dll" /?
Regex pattern: [^\\]+(?=\.exe)
No match.
---