J'ai le test simple suivant où j'essaye d'obtenir le modèle Regex de telle sorte qu'il arrache le nom de l'exécutable sans le suffixe ".exe".

Il semble que mon paramètre de groupe de non-capture (?:\\.exe) ne fonctionne pas ou je ne comprends pas comment il est censé fonctionner.

regex101 et regexstorm.net affiche le même résultat et le premier confirme que "(?: \. exe)" est une correspondance non capturante.

Des pensées sur ce que je fais mal?

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

J'ai pu extraire la valeur que je voulais en utilisant un modèle de correspondance avec des noms de groupe définis, comme indiqué ci-dessous, mais j'aimerais comprendre pourquoi l'approche de configuration de groupe sans capture n'a pas fonctionné comme je m'y attendais.

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

/ eoq

1
myusrn 12 août 2017 à 19:59

2 réponses

Il correspondrait au groupe non capturé mais ne le capturera pas, donc si vous voulez la partie non capturée, vous devez accéder au groupe de capture au lieu de la correspondance entière

Vous pouvez accéder aux groupes dans

var asmName = Regex.Match(testEcl, @"([^\\]+)(?:\.exe)", RegexOptions.IgnoreCase);
asmName.Groups[1].Value

La démo de l'expression régulière est disponible ici

1
marvel308 12 août 2017 à 17:28

Vous utilisez un groupe sans capture. L'accent est mis ici sur le mot groupe ; le groupe ne capture pas le .exe, mais le regex en général le fait toujours.

Vous souhaitez probablement utiliser une recherche positive, qui affirme simplement que la chaîne doit répondre à un critère pour que la correspondance soit valide, bien que ce critère ne soit pas capturé.

En d'autres termes, vous voulez (?=, pas (?:, au début de votre groupe.

Le premier est seulement si vous énumérez le { {X0}} propriété de { {X1}} objet; dans votre cas, vous utilisez simplement la Value propriété, il n'y a donc pas de distinction entre un groupe normal (\.exe) et un groupe non capturant (?:\.exe).

Pour voir la distinction, considérez ce programme de test:

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("---");
}

La sortie de ceci est:

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.
---

Le premier regex (@"[^\\]+(\.exe)") a \.exe comme groupe normal. Lorsque nous énumérons la propriété Groups, nous voyons que .exe est en effet un groupe capturé dans notre entrée. (Notez que l'expression régulière entière est elle-même un groupe, donc Groups[0] est égal à Value).

La deuxième expression régulière (@"[^\\]+(?:\.exe)") est celle fournie dans votre question. La seule différence par rapport au scénario précédent est que la propriété Groups ne contient pas .exe comme l'une de ses entrées.

La troisième regex (@"[^\\]+(?=\.exe)") est celle que je vous suggère d'utiliser. Maintenant, la partie .exe de l'entrée n'est pas du tout capturée par l'expression régulière, mais une expression régulière ne correspondra pas à une chaîne à moins qu'elle ne se termine par .exe, comme l'illustre le quatrième scénario.

3
Joe Sewell 13 août 2017 à 18:18