StringBuilder non era realmente inteso per tutti gli scopi di stringa. Se hai davvero bisogno di cercarne uno, devi scrivere il tuo metodo.
Esistono diversi algoritmi di ricerca delle stringhe adatti a casi diversi.
Quanto segue è una semplice implementazione dell'algoritmo Knuth-Morris-Pratt che interessa solo le partite ordinali (nessuna piegatura del caso, nessuna collazione legata alla cultura, solo un semplice punto di codice per codepoint match). Presenta un overhead iniziale Θ(m)
in cui m
corrisponde alla lunghezza della parola ricercata, quindi trova in Θ(n)
dove n
è la distanza dalla parola cercata o la lunghezza dell'intero generatore di stringhe se non è presente. Questo è il semplice confronto char-by-char che è Θ((n-m+1) m)
(dove la notazione O()
descrive i limiti superiori, Θ()
descrive entrambi i limiti superiore e inferiore).
Tutto ciò detto, sembra che la creazione di un elenco potrebbe essere un approccio migliore all'attività in corso.
public static class StringBuilderSearching
{
public static bool Contains(this StringBuilder haystack, string needle)
{
return haystack.IndexOf(needle) != -1;
}
public static int IndexOf(this StringBuilder haystack, string needle)
{
if(haystack == null || needle == null)
throw new ArgumentNullException();
if(needle.Length == 0)
return 0;//empty strings are everywhere!
if(needle.Length == 1)//can't beat just spinning through for it
{
char c = needle[0];
for(int idx = 0; idx != haystack.Length; ++idx)
if(haystack[idx] == c)
return idx;
return -1;
}
int m = 0;
int i = 0;
int[] T = KMPTable(needle);
while(m + i < haystack.Length)
{
if(needle[i] == haystack[m + i])
{
if(i == needle.Length - 1)
return m == needle.Length ? -1 : m;//match -1 = failure to find conventional in .NET
++i;
}
else
{
m = m + i - T[i];
i = T[i] > -1 ? T[i] : 0;
}
}
return -1;
}
private static int[] KMPTable(string sought)
{
int[] table = new int[sought.Length];
int pos = 2;
int cnd = 0;
table[0] = -1;
table[1] = 0;
while(pos < table.Length)
if(sought[pos - 1] == sought[cnd])
table[pos++] = ++cnd;
else if(cnd > 0)
cnd = table[cnd];
else
table[pos++] = 0;
return table;
}
}
fonte
2012-09-04 10:52:37
Se avete bisogno di usare un 'StringBuilder' allora avrete probabilmente bisogno di chiamare' ToString' ogni volta che si desidera ricerca, che non è una grande idea per quanto riguarda le prestazioni. 'StringBuilder' è usato per * costruire stringhe *; presumibilmente se stai costruendo delle stringhe allora hai già le parti costituenti; perché non cerchi direttamente all'interno di quelle parti costitutive? – LukeH
'StringBuilder' è probabilmente il tipo di dati meno adatto per memorizzare un elenco di nomi ricercabili. Perché non usare invece un 'Elenco' e usare il metodo 'Contains' di' List'? –
Rotem
Avete un esempio di cosa sia effettivamente questa stringa? Si dice che memorizza "Nomi dei corsi" - indipendentemente dal fatto che il "Corso" in realtà significhi "Corsi", i "Nomi" suggeriscono più di un nome - quindi presumibilmente questa è una stringa delimitata in qualche modo. In tal caso, passare a 'Lista' o 'HashSet ' dei nomi * individuali * avrebbe molto senso –