2009-03-20 12 views
13

Ho una stringa che contiene diversi commenti html. Devo contare le corrispondenze uniche di un'espressione.Come posso ottenere una corrispondenza regolare per essere aggiunta una sola volta alla raccolta delle partite?

Ad esempio, la stringa potrebbe essere:

var teststring = "<!--X1-->Hi<!--X1-->there<!--X2-->"; 

Attualmente uso questo per ottenere le partite:

var regex = new Regex("<!--X.-->"); 
var matches = regex.Matches(teststring); 

I risultati di questo è 3 partite. Tuttavia, mi piacerebbe avere solo 2 partite poiché ci sono solo due partite uniche.

So che probabilmente posso scorrere il MatchCollection risultante e rimuovere il Match aggiuntivo, ma spero che esista una soluzione più elegante.

Chiarimento: la stringa di esempio è notevolmente semplificata rispetto a ciò che viene effettivamente utilizzato. Ci può essere facilmente un X8 o X9, e ci sono probabilmente dozzine di ciascuno nella stringa.

risposta

22

vorrei solo usare il Enumerable.Distinct Method per esempio come questo:

string subjectString = "<!--X1-->Hi<!--X1-->there<!--X2--><!--X1-->Hi<!--X1-->there<!--X2-->"; 
var regex = new Regex(@"<!--X\d-->"); 
var matches = regex.Matches(subjectString); 
var uniqueMatches = matches 
    .OfType<Match>() 
    .Select(m => m.Value) 
    .Distinct(); 

uniqueMatches.ToList().ForEach(Console.WriteLine); 

Risulterà:

<!--X1--> 
<!--X2--> 

Per l'espressione regolare, si potrebbe forse usare questo?

(<!--X\d-->)(?!.*\1.*) 

sembra funzionare sulla vostra stringa di prova in RegexBuddy almeno =)

// (<!--X\d-->)(?!.*\1.*) 
// 
// Options: dot matches newline 
// 
// Match the regular expression below and capture its match into backreference number 1 «(<!--X\d-->)» 
// Match the characters “<!--X” literally «<!--X» 
// Match a single digit 0..9 «\d» 
// Match the characters “-->” literally «-->» 
// Assert that it is impossible to match the regex below starting at this position (negative lookahead) «(?!.*\1.*)» 
// Match any single character «.*» 
//  Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*» 
// Match the same text as most recently matched by capturing group number 1 «\1» 
// Match any single character «.*» 
//  Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*» 
+0

Mi è piaciuta questa idea ma purtroppo il i risultati non sono quelli che ci si aspettava. Nel mio test di unità (che ha una stringa molto più grande) ho ottenuto 8 risultati quando avrei dovuto ricevere 4. Non sono sicuro quale sia la differenza tra RegexBuddy e quello che sto usando. :( –

+0

Inoltre, ho provato a usare Distinct() ma MatchCollection, anche se deriva da IEnumerable, non sembra riconoscerlo –

+0

qual è la stringa più grande? Su MatchCollection è molto probabile che tu debba usare var stuff = theMatchCollection.OfType () .Select (m => m.Value) .Distinct(), o qualcosa di simile. – Svish

0

Estrarre i commenti e memorizzarli in un array. Quindi puoi filtrare i valori unici.

Ma non so come implementarlo in C#.

0

Cattura la parte interna del commento come un gruppo. Quindi metti quelle stringhe in una tabella hash (dizionario). Quindi chiedi al dizionario il suo conto, poiché eliminerà automaticamente le ripetizioni.

var teststring = "<!--X1-->Hi<!--X1-->there<!--X2-->"; 
var tokens = new Dicationary<string, string>(); 
Regex.Replace(teststring, @"<!--(.*)-->", 
    match => { 
    tokens[match.Groups[1].Value] = match.Groups[1].Valuel; 
    return ""; 
    }); 
var uniques = tokens.Keys.Count; 

Utilizzando il costrutto Regex.Replace si ottiene una chiamata lambda per ogni corrispondenza. Dato che non ti interessa la sostituzione, non la imposti come nulla.

È necessario utilizzare Gruppo [1] perché il gruppo [0] è l'intera corrispondenza. Sto solo ripetendo la stessa cosa da entrambi i lati, in modo che sia più facile da inserire nel dizionario, che memorizza solo chiavi univoche.

0

A seconda di quanti Xn del avete si potrebbe essere in grado di utilizzare:

(\<!--X1--\>){1}.*(\<!--X2--\>){1} 

che abbinerà solo ogni occorrenza del X1, X2 ecc una volta a condizione che siano in ordine.

2

Sembra che tu stai facendo due cose diverse:

  1. commenti di corrispondenza come/< - X. ->/
  2. Trovare la serie di commenti unici

Così è abbastanza logico gestirli come due passi distinti:

var regex = new Regex("<!--X.-->"); 
var matches = regex.Matches(teststring); 

var uniqueMatches = matches.Cast<Match>().Distinct(new MatchComparer()); 

class MatchComparer : IEqualityComparer<Match> 
{ 
    public bool Equals(Match a, Match b) 
    { 
     return a.Value == b.Value; 
    } 

    public int GetHashCode(Match match) 
    { 
     return match.Value.GetHashCode(); 
    } 
} 
+0

Hai provato questo? Per qualche motivo non riesco a ottenere Distinct() per lavorare con MatchCollection anche se questa è la seconda risposta che l'ha inclusa. Sto usando .NET3.5 e ho System.Linq nelle mie istruzioni using. –

+0

Corretto il codice in modo che funzioni. – user7116

+0

dovresti usare OfType e non Cast – Svish

Problemi correlati