283 votes

Comment accéder aux groupes de capture nommés dans une Regex .NET ?

J'ai du mal à trouver une bonne ressource qui explique comment utiliser les groupes de capture nommés en C#. Voici le code que j'ai jusqu'à présent :

string page = Encoding.ASCII.GetString(bytePage);
Regex qariRegex = new Regex("<td><a href=\"(?<link>.*?)\">(?<name>.*?)</a></td>");
MatchCollection mc = qariRegex.Matches(page);
CaptureCollection cc = mc[0].Captures;
MessageBox.Show(cc[0].ToString());

Cependant, cela ne montre toujours que la ligne complète :

<td><a href="http://stackoverflow.com/path/to/file">Name of File</a></td> 

J'ai essayé plusieurs autres "méthodes" que j'ai trouvées sur divers sites web, mais j'obtiens toujours le même résultat.

Comment puis-je accéder aux groupes de capture nommés qui sont spécifiés dans ma regex ?

3 votes

La rétro-référence doit être au format (?<link>.*) et non (?<link>.* ?)

14 votes

Pour information : si vous essayez de stocker un groupe de capture nommé à l'intérieur d'un fichier xml, alors la fonction <> le brisera. Vous pouvez utiliser (?'link'.*) à la place dans ce cas. Ce n'est pas tout à fait pertinent pour cette question, mais j'ai atterri ici après une recherche Google sur " .net named capture groups ", donc je suis sûr que d'autres personnes le sont aussi...

1 votes

Lien StackOverflow avec un bel exemple : stackoverflow.com/a/1381163/463206 Aussi, @rtpHarry, Non le <> ne le cassera pas. J'ai pu utiliser le myRegex.GetGroupNames() comme noms d'éléments XML.

286voto

Paolo Tedesco Points 22442

Utilisez la collection de groupes de l'objet Match, en l'indexant avec le nom du groupe de capture, par ex.

foreach (Match m in mc){
    MessageBox.Show(m.Groups["link"].Value);
}

11 votes

N'utilisez pas var m puisque ce serait une object .

122voto

Andrew Hare Points 159332

Vous spécifiez la chaîne de groupe de capture nommée en la passant à l'indexeur de l'objet Groups d'un résultat Match objet.

Voici un petit exemple :

using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        String sample = "hello-world-";
        Regex regex = new Regex("-(?<test>[^-]*)-");

        Match match = regex.Match(sample);

        if (match.Success)
        {
            Console.WriteLine(match.Groups["test"].Value);
        }
    }
}

11voto

Rashmi Pandit Points 9341

L'exemple de code suivant, correspondra au modèle même en cas de caractères d'espacement entre les deux. c'est-à-dire :

<td><a href='http://stackoverflow.com/path/to/file'>Name of File</a></td>

ainsi que :

<td> <a      href='http://stackoverflow.com/path/to/file' >Name of File</a>  </td>

La méthode renvoie true ou false, selon que la chaîne htmlTd en entrée correspond ou non au modèle. Si elle correspond, les paramètres de sortie contiennent le lien et le nom respectivement.

/// <summary>
/// Assigns proper values to link and name, if the htmlId matches the pattern
/// </summary>
/// <returns>true if success, false otherwise</returns>
public static bool TryGetHrefDetails(string htmlTd, out string link, out string name)
{
    link = null;
    name = null;

    string pattern = "<td>\\s*<a\\s*href\\s*=\\s*(?:\"(?<link>[^\"]*)\"|(?<link>\\S+))\\s*>(?<name>.*)\\s*</a>\\s*</td>";

    if (Regex.IsMatch(htmlTd, pattern))
    {
        Regex r = new Regex(pattern,  RegexOptions.IgnoreCase | RegexOptions.Compiled);
        link = r.Match(htmlTd).Result("${link}");
        name = r.Match(htmlTd).Result("${name}");
        return true;
    }
    else
        return false;
}

Je l'ai testé et cela fonctionne correctement.

1 votes

Merci de me rappeler que les accolades peuvent accéder aux groupes. Je préfère m'en tenir à ${1} pour rendre les choses encore plus simples.

0 votes

Cela répond complètement à la question, mais présente certains problèmes qui sont trop longs à expliquer ici, mais je les ai expliqués et corrigés dans ma réponse ci-dessous

2voto

tinamou Points 185

En outre, si quelqu'un a un cas d'utilisation où il a besoin de noms de groupe avant d'exécuter la recherche sur l'objet Regex, il peut utiliser :

var regex = new Regex(pattern); // initialized somewhere
// ...
var groupNames = regex.GetGroupNames();

2voto

Protron Points 3889

Cette réponse améliore La réponse de Rashmi Pandit qui est d'une certaine manière meilleur que les autres car il semble résoudre complètement le problème exact détaillé dans la question.

Le problème est que cette méthode est inefficace et n'utilise pas l'option IgnoreCase de manière cohérente.

La partie inefficace est due au fait que l'expression rationnelle peut être coûteuse à construire et à exécuter, et dans cette réponse elle aurait pu être construite une seule fois (en appelant Regex.IsMatch était juste en train de reconstruire la regex derrière la scène). Et Match aurait pu être appelée une seule fois et stockée dans une variable puis link y name devrait appeler Result de cette variable.

Et l'option IgnoreCase n'a été utilisée que dans l'option Match mais pas dans la partie Regex.IsMatch partie.

J'ai également déplacé la définition du Regex en dehors de la méthode afin de ne la construire qu'une seule fois (je pense que c'est l'approche la plus judicieuse si nous stockons que l'assemblage avec l'option RegexOptions.Compiled option).

private static Regex hrefRegex = new Regex("<td>\\s*<a\\s*href\\s*=\\s*(?:\"(?<link>[^\"]*)\"|(?<link>\\S+))\\s*>(?<name>.*)\\s*</a>\\s*</td>",  RegexOptions.IgnoreCase | RegexOptions.Compiled);

public static bool TryGetHrefDetails(string htmlTd, out string link, out string name)
{
    var matches = hrefRegex.Match(htmlTd);
    if (matches.Success)
    {
        link = matches.Result("${link}");
        name = matches.Result("${name}");
        return true;
    }
    else
    {
        link = null;
        name = null;
        return false;
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X