3 votes

Chaîne de groupe Regex où le délimiteur peut être utilisé deux fois (.net regex)

J'écris un analyseur syntaxique pour Excel qui peut mettre à jour les valeurs dans le document. Je suis actuellement en train d'analyser la partie en-tête/pied de page du format de document de la feuille de calcul. Le format d'un en-tête/pied de page dans Excel est stocké sous forme de texte brut, délimité par :

  • &L
  • &C
  • &R

Ainsi, votre en-tête / pied de page pourrait ressembler à ceci dans le xml :

&LTodaysDate&CDocumentTitle&RAuthors Name

Si vous n'avez qu'un en-tête gauche et un en-tête droit, votre chaîne xml ressemblera à ceci :

&LTodaysDate&RAuthors Name

J'ai essayé de créer un modèle capable de détecter chacun de ces groupes et d'en extraire le composant (par ex. &L , &C , &R ) ainsi que tout le texte qui suit cette balise.

La chaîne regex est la suivante : (&.{1})([A-Za-z\d_ ]*) ( Lien vers l'exemple )

Cependant, j'ai un problème marginal qui m'empêchera d'analyser correctement les en-têtes Excel contenant des esperluettes.

Dans un en-tête excel, pour que votre document ait une esperluette dans le titre (ceci est en texte brut), vous devez taper && . Ainsi, le xml d'un en-tête avec une esperluette pourrait ressembler à ceci :

&RPork && Beans (ce qui afficherait "Porc et haricots" dans la feuille de calcul).

Mon regex n'est pas capable de faire face à l'esperluette prématurée. Dans le premier groupe ( (&.{1}) ) Je demande tout ce qui a une esperluette et le caractère qui la suit (c'est-à-dire un L/C/R). Comment puis-je dire à ce groupe de ne pas l'inclure lorsqu'il y a deux esperluettes ? Mes compétences en matière d'expressions rationnelles sont plutôt novices, mais je peux décrire ce que je veux à un niveau supérieur :

Je veux diviser la chaîne de caractères à chaque fois que je vois &L/&C/&R et capturer tout le texte après, jusqu'à un autre délimiteur &L/&C/&R (en excluant les espaces de nouvelle ligne, etc.). Je peux décrire cela au mieux en C# linq ci-dessous.

(&.{1}.Where(c => c != '&'))([A-Za-z\d_ ]*)

Pour la chaine de caractères "&RPork && Beans"

ma regex capture 2 correspondances avec chacune 2 groupes :

match 1
groupe 1 : "&R" groupe 2 : "Pork" (porc)

match 2
groupe 1 : "&&" groupe 2 : " Haricots "

et je voudrais que ça corresponde une fois :
groupe 1 : "&R" groupe 2 : "Porc & & haricots"

Merci pour votre aide

1voto

Wiktor Stribiżew Points 100073

Vous pouvez utiliser

var result = Regex.Split(s, "(&[LRC])").Where(x => !string.IsNullOrWhiteSpace(x));

Voir le Démonstration de regex . En (&[LRC]) correspondra à & et un L , R o C après elle, cette valeur sera extraite dans le tableau résultant grâce aux parenthèses de capture.

enter image description here

Un autre exemple d'utilisation :

var s = "&RPork && Beans&CDocument Title";
var result = Regex.Split(s, "(&[LRC])")
        .Where(x => !string.IsNullOrWhiteSpace(x))
        .ToList();
var data = result.Where((c,i) => i % 2 == 0).Zip(result.Where((c,i) => i % 2 != 0),
        (delimiter, value) => new KeyValuePair<string, string>(delimiter, value));
foreach (var kvp in data)
    Console.WriteLine("Delimiter: {0}\nValue: {1}", kvp.Key, kvp.Value);

Sortie :

Delimiter: &R
Value: Pork && Beans
Delimiter: &C
Value: Document Title

1voto

Mahmoud-Abdelslam Points 159

Après avoir compris le cas, j'ai écrit une expression rationnelle qui correspond à ce dont vous avez besoin ( Lien vers l'exemple )

et voici l'expression :

(&(?=[RCL])[RCL]{1})([A-Za-z \d_ ] (&( ?![RCL])) [A-Za-z \d_ ] )

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