web-dev-qa-db-fra.com

C # Regex.Match accolades - contenu seulement? (exclure les accolades)

J'ai été incapable de trouver une réponse à ce sujet: puis-je utiliser la méthode Regex.Matches pour ne renvoyer que le contenus des éléments avec des accolades?

Si j'utilise Regex ({[^}]*}), ma valeur MatchCollection inclut les accolades. Je veux faire correspondre, mais alors seulement renvoyer le contenu. Voici ce que j'ai jusqu'à présent:

Regex regex = new Regex(({[^}]*}), RegexOptions.IgnoreCase);
MatchCollection matches = regex.Matches("Test {Token1} {Token 2}");
// Results include braces (undesirable)
var results = matches.Cast<Match>().Select(m => m.Value).Distinct().ToList();
18
PeterX

Je l'ai toujours aimé explicite. Vous pouvez donc utiliser les groupes "positif lookbehind" (? <= ...) et "positif lookahead" (? = ...):

(?<=\{)
[^}]*
(?=\})

ce qui signifie:

  • nécessite l'ouverture de l'accolade avant match
  • collecter du texte (bien sûr) - comme indiqué avant que je puisse être aussi [^ {}] *
  • nécessite une accolade fermante après match
24
Milosz Krajewski

En C #, comme dans de nombreux autres langages de programmation, le moteur des expressions rationnelles prend en chargegroupes de capture, qui sont sous-correspondances, des parties de sous-chaînes correspondant à un motif de regex complet, défini dans un motif regex à l’aide de parenthèses (par exemple, 1([0-9])3 correspond à 123 et enregistre la valeur de 2 dans un tampon du groupe de capture 1). Les textes capturés sont accessibles via Match.Groups[n].Valuen est l’index du groupe de capture à l’intérieur du motif.

La capture est beaucoup plus efficace que les lookarounds . Lorsque des conditions complexes ne sont pas nécessaires, les groupes de capture sont de bien meilleures alternatives.

Voir mon test de vitesse regex effectué sur regexhero.net:

 enter image description here

Maintenant, comment pouvons-nous obtenir la sous-chaîne entre accolades?

  • s'il n'y a pas d'autre accolade à l'intérieur, avec une classe de caractères annulée: {([^{}]*)
  • s'il peut y avoir des accolades imbriquées: {((?>[^{}]+|{(?<c>)|}(?<-c>))*(?(c)(?!)))

Dans les deux cas, nous correspondons à un { d'ouverture, puis à (1) tout caractère autre que { ou }, ou (2) tous les caractères jusqu'au premier } apparié.

Voici exemple de code :

var matches = Regex.Matches("Test {Token1} {Token 2}", @"{([^{}]*)");
var results = matches.Cast<Match>().Select(m => m.Groups[1].Value).Distinct().ToList();
Console.WriteLine(String.Join(", ", results));
matches = Regex.Matches("Test {Token1} {Token {2}}", @"{((?>[^{}]+|{(?<c>)|}(?<-c>))*(?(c)(?!)))");
results = matches.Cast<Match>().Select(m => m.Groups[1].Value).Distinct().ToList();
Console.WriteLine(String.Join(", ", results));

Résultat: Token1, Token 2, Token1, Token {2}.

Notez que RegexOptions.IgnoreCase est redondant lorsque vous n'avez aucune lettre littérale pouvant avoir une casse différente dans le modèle.

11
Wiktor Stribiżew

Merci Milosz Krajewski, Rien à ajouter mais voici la fonction

private List<String> GetTokens(String str)
{
    Regex regex = new Regex(@"(?<=\{)[^}]*(?=\})", RegexOptions.IgnoreCase);
    MatchCollection matches = regex.Matches(str);

    // Results include braces (undesirable)
    return matches.Cast<Match>().Select(m => m.Value).Distinct().ToList();
}
5
bunjeeb

Il suffit de déplacer les accolades en dehors des parenthèses:

 {([^}]*)}
3
RichieHindle

C'est regex pour C # .net.

@"{(.*?)}"

il affiche un

jeton1 jeton2

2
RajeshValangaiman

Si je comprends ce que tu veux. Changez l'expression régulière en {([^}]*)}. Cela ne fera que capturer le texte entre {}, sans les inclure.

0
UberMouse

Peu modifiant la réponse de @Milosz Krajewski

(?<=\{)[^}{]*(?=\})

cela permettra d’éviter les accolades fermées dans la ficelle.

0
sumit sharma