2012-04-11 13 views
5

Devo controllare se una stringa contiene parole parolacce.C# - Il modo più veloce per trovare uno dei set di stringhe in un'altra stringa

seguito qualche consiglio da un'altra domanda qui, ho fatto un HashSet contenente le parole:

HashSet<string> swearWords = new HashSet<string>() { "word_one", "word_two", "etc" }; 

Ora ho bisogno di vedere se uno dei valori contenuti nel swearWords sono nella mia stringa.

ho visto fare il contrario, ad esempio:

swearWords.Contains(myString) 

Ma questo restituisce false.

Qual è il modo più veloce per verificare se una delle parole nell'Hashset è in myString?

NB: Immagino di poter utilizzare un ciclo di foreach per controllare ogni parola a turno, e interrompere se viene trovata una corrispondenza, mi chiedo solo se c'è un modo più veloce.

+0

Perché sei usando un 'HashSet'? Potrebbe essere più facile usare 'Lista qui. E poi dividi 'myString' in una lista e fai il confronto necessario. – SkonJeet

+1

@SkonJeet: se l'elenco delle parolacce è grande, il controllo del contenimento sarà più veloce per un 'HashSet' di un' Elenco' - e non riesco a vedere che un 'Elenco' lo renderebbe * più * *. –

+0

Inizialmente utilizzavo un elenco e poi lo convertivo in un HashSet mentre leggevo che sono più veloci per controllare i valori in – surfitscrollit

risposta

6

Si potrebbe provare una regex, ma non sono sicuro che sia Più veloce.

Regex rx = new Regex("(" + string.Join("|", swearWords) + ")"); 
rx.IsMatch(myString) 
+2

+1 - Swear le parole sono meglio descritte come espressioni regolari, sto parlando dalla mia esperienza, ma è praticamente impossibile battere gli utenti con un algoritmo statico e un elenco di parole –

9

Se si posiziona il giura in un IEnumerable <> contenitore di attuazione:

var containsSwears = swarWords.Any(w => myString.Contains(w)); 

Nota: HashSet <> implementa IEnumerable <>

+2

'HashSet ' implementa 'IEnumerable '. (E devi stare attento al problema di Scunthorpe se stai usando questo approccio: http://en.wikipedia.org/wiki/Scunthorpe_problem) – LukeH

+0

@LukeH: buon punto ma oltre lo scopo di questa discussione. Forse meglio come commento alla domanda. +1 – Sprague

+0

lol @ scunthorpe, bel nome. Tuttavia, se la tua logica per rompere le parole non funziona, dovresti essere chiaro di questo problema perché stai controllando intere parole, non stringhe all'interno delle parole. Un problema che potresti avere è la corrispondenza tra maiuscole e minuscole delle parole o delle parole che usano le parole leet. –

3

Si potrebbe dividere "myString" in un tipo di IEnumerable, e quindi utilizzare "sovrapposizioni" su di loro?

http://msdn.microsoft.com/en-us/library/bb355623(v=vs.90).aspx

(P.S. tempo che non ci vediamo ...)

EDIT: Basta errore notato nella mia risposta precedente.

+0

Hey Adam! Sì, è heh – surfitscrollit

+0

In effetti, ho appena doppio controllo, Sovrapposizioni sembra che farebbe esattamente quello che ti serve? Non sono sicuro sull'efficienza. – KingCronus

3

Il problema principale di questi regimi sia definire che cosa una parola è nel contesto della stringa che si desidera controllare .

  • Implementazioni ingenue come quelle che utilizzano input.Contains semplicemente non hanno il concetto di una parola; essi "scopriranno" parolacce anche quando ciò non era l'intento.
  • Rompere le parole su spazi vuoti non lo taglierà (considerate anche i segni di punteggiatura, ecc.).
  • Spezzare su caratteri diversi dallo spazio bianco solleverà problemi di cultura: quali caratteri sono considerati esattamente come caratteri parola?

Supponendo che l'elenco delle parole d'arresto utilizzi solo l'alfabeto latino, una scelta pratica sarebbe assumere che le parole siano sequenze composte solo da caratteri latini.Quindi una soluzione di partenza ragionevole sarebbe

var words = Regex.Split(@"[^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Pc}\p{Lm}]", myString); 

La regex sopra è la classe standard di \W modificato per non includere cifre; per maggiori informazioni, vedi http://msdn.microsoft.com/en-us/library/20bw873z.aspx. Per altri approcci, vedere this question ed eventualmente il collegamento CodeProject fornito nella risposta accettata.

che ha suddiviso la stringa di input, è possibile iterare words e sostituire quelli che corrispondono qualcosa nella vostra lista (utilizzare swearWords.Contains(word) per controllare) o semplicemente rilevare se ci sono delle corrispondenze a tutti con

var anySwearWords = words.Intersect(swearWords).Any(); 
Problemi correlati