2015-05-15 15 views
9

Questa è la mia situazione: ho una stringa che rappresenta un testoVerificare se una stringa contiene un elenco di sottostringhe e salvare quelli corrispondenti

string myText = "Text to analyze for words, bar, foo"; 

e un elenco di parole da cercare in esso

List<string> words = new List<string> {"foo", "bar", "xyz"}; 

vorrei conoscere il metodo più efficiente, se esiste, per ottenere la lista delle parole contenute nel testo, una cosa del genere:

List<string> matches = myText.findWords(words) 
+0

efficiente in termini di tempo di CPU o la memoria? – adv12

+0

Quale sarebbe la dimensione di 'myText' e quante operazioni di ricerca farai/ – npinti

+0

È necessario definire cosa intendi per" parola ". Dovrebbe "abbinarsi" in una stringa come "This is foobar"? Le risposte "Contiene" corrisponderebbero a quelle, mentre le risposte "Dividi" non lo farebbero. – juharr

risposta

7

Non ci sono analisi speciali in questa query eccetto che devi usare il metodo Contains. Così si può provare questo:

string myText = "Text to analyze for words, bar, foo"; 

List<string> words = new List<string> { "foo", "bar", "xyz" }; 

var result = words.Where(i => myText.Contains(i)).ToList(); 
//result: bar, foo 
+0

Questa è probabilmente l'opzione migliore, considerando l'efficienza del tempo di codifica (che non dovrebbe essere ignorata) –

+0

@DrewKennedy per quanto il problema non sia complicato, perché non andare per la soluzione più semplice e compatta –

+0

@HosseinNarimaniRad Sono d'accordo che non lo fa non importa. Penso che il commento si riferisce a questo metodo che richiede più passaggi sulla stringa, che non è necessario. Inoltre, esiste l'algoritmo Boyer-Moore-Horspool che potrebbe velocizzare significativamente l'algoritmo se le parole sono relativamente lunghe. – Bas

5

è possibile utilizzare un HashSet<string> e si intersecano entrambe le collezioni:

string myText = "Text to analyze for words, bar, foo"; 
string[] splitWords = myText.Split(' ', ','); 

HashSet<string> hashWords = new HashSet<string>(splitWords, 
               StringComparer.OrdinalIgnoreCase); 
HashSet<string> words = new HashSet<string>(new[] { "foo", "bar" }, 
              StringComparer.OrdinalIgnoreCase); 

hashWords.IntersectWith(words); 
+1

Mentre questo gestisce l'esempio dato, non funzionerebbe con una stringa come "Qui è foo! Dove è bar? I am xyz.". Fondamentalmente avresti bisogno di dividere tutto ciò che può separare le parole. Anche l'OP non ha menzionato se "foo" dovrebbe essere abbinato in una stringa come "This is foobar". – juharr

+0

@juharr Questo è un esempio di ciò che l'OP può fare con un 'HashSet'. Può dividersi su qualsiasi separatore che desidera. Può anche tagliare le corde prima di inserirle nella collezione, cosa che non ho fatto. –

+0

Sono assolutamente d'accordo che questa è la strada da percorrere se l'OP vuole guardare le parole e non solo qualsiasi sottostringa. Ho solo pensato che fosse necessario sottolineare che il processo di scissione potrebbe essere più complicato. – juharr

0

Giocando fuori l'idea che si vuole essere in grado di utilizzare myText.findWords(words), è possibile effettuare una proroga metodo per la classe String per fare solo quello che vuoi.

public static class StringExtentions 
{ 
    public static List<string> findWords(this string str, List<string> words) 
    { 
     return words.Where(str.Contains).ToList(); 
    } 
} 

utilizzo:

string myText = "Text to analyze for words, bar, foo"; 
List<string> words = new List<string> { "foo", "bar", "xyz" }; 
List<string> matches = myText.findWords(words); 
Console.WriteLine(String.Join(", ", matches.ToArray())); 
Console.ReadLine(); 

Risultati:

foo, bar soluzione

2

una regex

var words = new string[]{"Lucy", "play", "soccer"}; 
var text = "Lucy loves going to the field and play soccer with her friend"; 
var match = new Regex(String.Join("|",words)).Match(text); 
var result = new List<string>(); 

while (match.Success) { 
    result.Add(match.Value); 
    match = match.NextMatch(); 
} 

//Result ["Lucy", "play", "soccer"] 
+0

Dovresti usare Regex.Escape – mrwaim

0

Ecco una soluzione semplice che rappresenta gli spazi e la punteggiatura:

static void Main(string[] args) 
{ 
    string sentence = "Text to analyze for words, bar, foo";    
    var words = Regex.Split(sentence, @"\W+"); 
    var searchWords = new List<string> { "foo", "bar", "xyz" }; 
    var foundWords = words.Intersect(searchWords); 

    foreach (var item in foundWords) 
    { 
     Console.WriteLine(item); 
    } 

    Console.ReadLine(); 
} 
Problemi correlati