Question

Voici l'entrée (HTML, pas XML):

... html content ...
<tag1> content for tag 1 </tag1>
<tag2> content for tag 2 </tag2>
<tag3> content for tag 3 </tag3>
... html content ...

Je voudrais avoir 3 matches, chacun avec deux groupes. Le premier groupe contiendrait le nom de la balise et le second groupe contiendrait le texte intérieur de la balise. Il n'y a que ces trois balises, il n'a donc pas besoin d'être universel.

En d'autres termes:

match.Groups["name"] would be "tag1"
match.Groups["value"] would be "content for tag 2"

Des idées?

Était-ce utile?

La solution

Je ne vois pas pourquoi vous voudriez utiliser des noms de groupes de correspondance pour cela.

Voici une expression régulière qui ferait correspondre le nom et le contenu de la balise en correspondances numérotées.

<(tag1|tag2|tag3)>(.*?)</$1>

Voici une variante avec des noms de groupe de style .NET

<(?'name'tag1|tag2|tag3)>(?'value'.*?)</\k'name'>.

EDIT

RegEx adapté selon la clarification de l'auteur de la question.

Autres conseils

Les expressions rationnelles pour cela pourraient être:

/<([^>]+)>([^<]+)<\/\1>/

Mais c’est général, car je ne connais pas grand chose au machanisme qui s’échappe de .NET. Pour le traduire:

  • le premier groupe correspond au nom de la première balise entre < et >
  • le deuxième groupe correspond au contenu (de > au prochain <
  • la vérification de fin si la première balise est fermée

HTH

Merci à tous mais aucun des regexes ne fonctionne. :( Peut-être que je n’étais pas assez précis, désolé pour cela. Voici le code HTML exact que je suis en train d’analyser:

...some html content <b> etc </b> ...
<user> hello <b>mitch</b> </user>
...some html content <b> etc </b> ...
<message> some html <i>message</i> <a href....>bla</a> </message>
...some html content <b> etc </b> ...

J'espère que c'est plus clair maintenant. Je suis après les balises USER et MESSAGE.

Je dois obtenir deux matches, chacun avec deux groupes. Le premier groupe me donnerait le nom de la balise (utilisateur ou message) et le second groupe me donnerait l'intégralité du texte intérieur de la balise.

Les données sont-elles correctes au format xml ou y a-t-il juste l'aspect?

S'il s'agit de html, le Pack d'agilité HTML mérite une enquête. Il fournit un DOM ( similaire à XmlDocument) que vous pouvez utiliser pour interroger les données:

string input = @"<html>...some html content <b> etc </b> ...
<user> hello <b>mitch</b> </user>
...some html content <b> etc </b> ...
<message> some html <i>message</i> <a href....>bla</a> </message>
...some html content <b> etc </b> ...</html>";

            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(input);
            foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//user | //message"))
            {
                Console.WriteLine("{0}: {1}", node.Name, node.InnerText);
                // or node.InnerHtml to keep the formatting within the content
            }

Cette sortie:

user:  hello mitch
message:  some html message bla

Si vous voulez les balises de formatage, utilisez .InnerHtml au lieu de .InnerText.

S'il s'agit de XML, alors pour coder avec le spectre complet de XML, il serait préférable d'utiliser un analyseur XML. Pour le xml de taille petite à moyenne, le charger dans un DOM tel que XmlDocument conviendrait, puis interrogez les nœuds (par exemple, & Quot; // * & Quot;). Pour xml énorme, XmlReader peut être une option.

Si les données n'ont pas à s'inquiéter du code XML complet, certaines expressions rationnelles simples ne devraient pas être trop compliquées ... un exemple simplifié (aucun attribut, aucun espace de nom, aucun xml imbriqué) pourrait être:

string input = @"blah <tag1> content for tag 1 </tag1> blop
<tag2> content for tag 2 </tag2> bloop
<tag3> content for tag 3 </tag3> blip";

        const string pattern = @"<(\w+)>\s*([^<>]*)\s*</(\1)>";
        Console.WriteLine(Regex.IsMatch(input, pattern));
        foreach(Match match in Regex.Matches(input, pattern)) {
            Console.WriteLine("{0}: {1}", match.Groups[1], match.Groups[2]);
        }

Le problème était que les personnes ([^ <] *) utilisaient pour faire correspondre les éléments à l'intérieur des balises correspondaient à l'ouverture < des balises imbriquées, puis la balise de fermeture de la balise imbriquée ne correspond pas à la balise externe et donc l'expression régulière a échoué.

Voici une version légèrement plus robuste du regex de Tomalak permettant les attributs et les espaces:

Regex tagRegex = new Regex(@"<\s*(?<tag>" + string.Join("|", tags) + @")[^>]*>(?<content>.*?)<\s*/\s*\k<tag>\s*>", RegexOptions.IgnoreCase);

Évidemment, si vous ne devez utiliser qu'un ensemble spécifique de balises, vous pouvez remplacer le

string.Joing("|", tags)

avec la liste de balises séparées par un tuyau codé en dur.

Les limitations de l'expression rationnelle sont les suivantes: si vous essayez de faire correspondre une balise imbriquée dans une autre, elle ne fera que correspondre à la balise externe. c'est-à-dire

  

< utilisateur > abc < message > def < / message > < / user >

Cela correspond à la balise utilisateur externe, mais pas à la balise de message interne.

Il ne gère pas non plus & les citations de gt;; comme ceci:

  

< utilisateur attrib = & "oops > &"; >

Cela correspondra tout simplement

  

< utilisateur attrib = &

en tant que balise et

  

& "; >

fera partie du contenu des tags.

Cela vous donnera des groupes de capture nommés pour ce que vous voulez. Cela ne fonctionnera pas pour les tags imbriqués, cependant.

/<(?<name>[^>]+)>(?<value>[^<]+)</\1>/

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top