2013-03-22 16 views
38

Supponiamo che io sono una stringa del tipo:Come contare le occorrenze sub-stringa?

MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com"; 

allora voglio sapere quanto tempo di occorrenze della sub-string "OU =" in questa stringa. Con singolo carattere, forse c'è qualcosa di simile:

int count = MyString.Split("OU=").Length - 1; 

ma Split funziona solo per char, non string.

Anche come trovare la posizione di n occorrenze? Ad esempio, la posizione del secondo "OU=" nella stringa?

Come risolvere questo problema?

+1

'String.Split' ha diversi sovraccarichi che consentono di dividere per stringhe. Vedi http://msdn.microsoft.com/en-us/library/tabh47cf.aspx – shf301

+0

split non funziona solo per i caratteri ... – MUG4N

+0

Avresti potuto farlo usando Multiple Delim Sarei più che felice di postarti un semplice esempio in codice per uso futuro. 'e Split funziona su una stringa' 'Ricorda che Split() restituisce una matrice in modo che nel caso della stringa restituisca string [] sarà necessario creare una nuova stringa [] {" somestring "," someotherString ".. ecc. ..} ' – MethodMan

risposta

96
Regex.Matches(input, "OU=").Count 
+0

Grazie. Anche come trovare la posizione di n occorrenze? per esempio, la posizione della 2a volta "OU =" nella stringa? – KentZhou

+0

Scavalcato un po 'e ho trovato questa domanda su SO che dovrebbe aiutarti: http://stackoverflow.com/questions/767767/finding-multiple-indexes-from-source-string – tnw

+0

@KentZhou Ti dispiacerebbe accettare la mia risposta se questo è la soluzione alla tua domanda? – tnw

2
int count = myString.Split(new []{','}) 
        .Count(item => item.StartsWith(
         "OU=", StringComparison.OrdinalIgnoreCase)) 
+1

Non toot il mio corno personale , ma ciò dipende dalla separazione virgola. Certo, funziona in questo scenario molto specifico, ma la mia soluzione Regex è più semplice e più dinamica. – tnw

+0

Sì, sono d'accordo, solo dando un'alternativa. – Phil

+0

Assolutamente, posso apprezzarlo.+1 – tnw

2

seguito dovrebbe funzionare

MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com"; 
    int count = Regex.Matches(MyString, "OU=").Count 
10

Potete trovare tutte le occorrenze e le loro posizioni con IndexOf:

string MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com"; 
string stringToFind = "OU="; 

List<int> positions = new List<int>(); 
int pos = 0; 
while ((pos < MyString.Length) && (pos = MyString.IndexOf(stringToFind, pos)) != -1) 
{ 
    positions.Add(pos); 
    pos += stringToFind.Length(); 
} 

Console.WriteLine("{0} occurrences", positions.Count); 
foreach (var p in positions) 
{ 
    Console.WriteLine(p); 
} 

È possibile ottenere lo stesso risultato da un'espressione regolare:

var matches = Regex.Matches(MyString, "OU="); 
Console.WriteLine("{0} occurrences", matches.Count); 
foreach (var m in matches) 
{ 
    Console.WriteLine(m.Index); 
} 

Le differenze principali:

  • Il codice Regex è più breve
  • Il codice Regex alloca una collezione e più stringhe.
  • Il codice IndexOf può essere scritto per generare immediatamente la posizione, senza creare una raccolta.
  • È probabile che il codice Regex sarà più veloce in isolamento, ma se utilizzato più volte il sovraccarico combinato delle allocazioni di stringhe potrebbe causare un carico molto più elevato sul garbage collector.

Se stavo scrivendo questo in linea, come qualcosa che non è stato usato spesso, probabilmente andrei con la soluzione regex. Se dovessi metterlo in una libreria come qualcosa da usare molto, probabilmente andrei con la soluzione IndexOf.

+0

+1 nice writeup – tnw

+1

Piccolo errore di battitura? Lista posizioni = nuova lista []; dovrebbe essere la lista posizioni = nuova lista (); – RickL

+0

Credo che questa sia una soluzione migliore. Se la stringa che stai cercando corrisponde è qualcosa di simile a .s allora la regex restituirà il numero errato. Con il ciclo while proposto da Jim, il numero di .s è corretto. – ashlar64

5

(Clippy-mode: ON )

Si guarda come si sta analizzando una query LDAP!

Volete analizzarlo:

  • manualmente? Vai a "SplittingAndParsing"
  • Automagicamente tramite chiamate Win32?Goto "Utilizzo Win32 tramite PInvoke"

(Clippy-mode: OFF)

"SplittingAndParsing":

var MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com"; 
var chunksAsKvps = MyString 
    .Split(',') 
    .Select(chunk => 
     { 
      var bits = chunk.Split('='); 
      return new KeyValuePair<string,string>(bits[0], bits[1]); 
     }); 

var allOUs = chunksAsKvps 
    .Where(kvp => kvp.Key.Equals("OU", StringComparison.OrdinalIgnoreCase)); 

"Uso Win32 tramite PInvoke":

Uso:

var parsedDn = Win32LDAP.ParseDN(str);  
var allOUs2 = parsedDn 
    .Where(dn => dn.Key.Equals("OU", StringComparison.OrdinalIgnoreCase)); 

Codice Utility:

// I don't remember where I got this from, honestly...I *think* it came 
// from another SO user long ago, but those details I've lost to history... 
public class Win32LDAP 
{ 
    #region Constants 
    public const int ERROR_SUCCESS = 0; 
    public const int ERROR_BUFFER_OVERFLOW = 111; 
    #endregion Constants 

    #region DN Parsing 
    [DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)] 
    protected static extern int DsGetRdnW(
     ref IntPtr ppDN, 
     ref int pcDN, 
     out IntPtr ppKey, 
     out int pcKey, 
     out IntPtr ppVal, 
     out int pcVal 
    ); 

    public static KeyValuePair<string, string> GetName(string distinguishedName) 
    { 
     IntPtr pDistinguishedName = Marshal.StringToHGlobalUni(distinguishedName); 
     try 
     { 
      IntPtr pDN = pDistinguishedName, pKey, pVal; 
      int cDN = distinguishedName.Length, cKey, cVal; 

      int lastError = DsGetRdnW(ref pDN, ref cDN, out pKey, out cKey, out pVal, out cVal); 

      if(lastError == ERROR_SUCCESS) 
      { 
       string key, value; 

       if(cKey < 1) 
       { 
        key = string.Empty; 
       } 
       else 
       { 
        key = Marshal.PtrToStringUni(pKey, cKey); 
       } 

       if(cVal < 1) 
       { 
        value = string.Empty; 
       } 
       else 
       { 
        value = Marshal.PtrToStringUni(pVal, cVal); 
       } 

       return new KeyValuePair<string, string>(key, value); 
      } 
      else 
      { 
       throw new Win32Exception(lastError); 
      } 
     } 
     finally 
     { 
      Marshal.FreeHGlobal(pDistinguishedName); 
     } 
    } 

    public static IEnumerable<KeyValuePair<string, string>> ParseDN(string distinguishedName) 
    { 
     List<KeyValuePair<string, string>> components = new List<KeyValuePair<string, string>>(); 
     IntPtr pDistinguishedName = Marshal.StringToHGlobalUni(distinguishedName); 
     try 
     { 
      IntPtr pDN = pDistinguishedName, pKey, pVal; 
      int cDN = distinguishedName.Length, cKey, cVal; 

      do 
      { 
       int lastError = DsGetRdnW(ref pDN, ref cDN, out pKey, out cKey, out pVal, out cVal); 

       if(lastError == ERROR_SUCCESS) 
       { 
        string key, value; 

        if(cKey < 0) 
        { 
         key = null; 
        } 
        else if(cKey == 0) 
        { 
         key = string.Empty; 
        } 
        else 
        { 
         key = Marshal.PtrToStringUni(pKey, cKey); 
        } 

        if(cVal < 0) 
        { 
         value = null; 
        } 
        else if(cVal == 0) 
        { 
         value = string.Empty; 
        } 
        else 
        { 
         value = Marshal.PtrToStringUni(pVal, cVal); 
        } 

        components.Add(new KeyValuePair<string, string>(key, value)); 

        pDN = (IntPtr)(pDN.ToInt64() + UnicodeEncoding.CharSize); //skip over comma 
        cDN--; 
       } 
       else 
       { 
        throw new Win32Exception(lastError); 
       } 
      } while(cDN > 0); 

      return components; 
     } 
     finally 
     { 
      Marshal.FreeHGlobal(pDistinguishedName); 
     } 
    } 

    [DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)] 
    protected static extern int DsQuoteRdnValueW(
     int cUnquotedRdnValueLength, 
     string psUnquotedRdnValue, 
     ref int pcQuotedRdnValueLength, 
     IntPtr psQuotedRdnValue 
    ); 

    public static string QuoteRDN(string rdn) 
    { 
     if (rdn == null) return null; 

     int initialLength = rdn.Length; 
     int quotedLength = 0; 
     IntPtr pQuotedRDN = IntPtr.Zero; 

     int lastError = DsQuoteRdnValueW(initialLength, rdn, ref quotedLength, pQuotedRDN); 

     switch (lastError) 
     { 
      case ERROR_SUCCESS: 
       { 
        return string.Empty; 
       } 
      case ERROR_BUFFER_OVERFLOW: 
       { 
        break; //continue 
       } 
      default: 
       { 
        throw new Win32Exception(lastError); 
       } 
     } 

     pQuotedRDN = Marshal.AllocHGlobal(quotedLength * UnicodeEncoding.CharSize); 

     try 
     { 
      lastError = DsQuoteRdnValueW(initialLength, rdn, ref quotedLength, pQuotedRDN); 

      switch(lastError) 
      { 
       case ERROR_SUCCESS: 
        { 
         return Marshal.PtrToStringUni(pQuotedRDN, quotedLength); 
        } 
       default: 
        { 
         throw new Win32Exception(lastError); 
        } 
      } 
     } 
     finally 
     { 
      if(pQuotedRDN != IntPtr.Zero) 
      { 
       Marshal.FreeHGlobal(pQuotedRDN); 
      } 
     } 
    } 


    [DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)] 
    protected static extern int DsUnquoteRdnValueW(
     int cQuotedRdnValueLength, 
     string psQuotedRdnValue, 
     ref int pcUnquotedRdnValueLength, 
     IntPtr psUnquotedRdnValue 
    ); 

    public static string UnquoteRDN(string rdn) 
    { 
     if (rdn == null) return null; 

     int initialLength = rdn.Length; 
     int unquotedLength = 0; 
     IntPtr pUnquotedRDN = IntPtr.Zero; 

     int lastError = DsUnquoteRdnValueW(initialLength, rdn, ref unquotedLength, pUnquotedRDN); 

     switch (lastError) 
     { 
      case ERROR_SUCCESS: 
       { 
        return string.Empty; 
       } 
      case ERROR_BUFFER_OVERFLOW: 
       { 
        break; //continue 
       } 
      default: 
       { 
        throw new Win32Exception(lastError); 
       } 
     } 

     pUnquotedRDN = Marshal.AllocHGlobal(unquotedLength * UnicodeEncoding.CharSize); 

     try 
     { 
      lastError = DsUnquoteRdnValueW(initialLength, rdn, ref unquotedLength, pUnquotedRDN); 

      switch(lastError) 
      { 
       case ERROR_SUCCESS: 
        { 
         return Marshal.PtrToStringUni(pUnquotedRDN, unquotedLength); 
        } 
       default: 
        { 
         throw new Win32Exception(lastError); 
        } 
      } 
     } 
     finally 
     { 
      if(pUnquotedRDN != IntPtr.Zero) 
      { 
       Marshal.FreeHGlobal(pUnquotedRDN); 
      } 
     } 
    } 
    #endregion DN Parsing 
} 

public class DNComponent 
{ 
    public string Type { get; protected set; } 
    public string EscapedValue { get; protected set; } 
    public string UnescapedValue { get; protected set; } 
    public string WholeComponent { get; protected set; } 

    public DNComponent(string component, bool isEscaped) 
    { 
     string[] tokens = component.Split(new char[] { '=' }, 2); 
     setup(tokens[0], tokens[1], isEscaped); 
    } 

    public DNComponent(string key, string value, bool isEscaped) 
    { 
     setup(key, value, isEscaped); 
    } 

    private void setup(string key, string value, bool isEscaped) 
    { 
     Type = key; 

     if(isEscaped) 
     { 
      EscapedValue = value; 
      UnescapedValue = Win32LDAP.UnquoteRDN(value); 
     } 
     else 
     { 
      EscapedValue = Win32LDAP.QuoteRDN(value); 
      UnescapedValue = value; 
     } 

     WholeComponent = Type + "=" + EscapedValue; 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj is DNComponent) 
     { 
      DNComponent dnObj = (DNComponent)obj; 
      return dnObj.WholeComponent.Equals(this.WholeComponent, StringComparison.CurrentCultureIgnoreCase); 
     } 
     return base.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     return WholeComponent.GetHashCode(); 
    } 
} 

public class DistinguishedName 
{ 
    public DNComponent[] Components 
    { 
     get 
     { 
      return components.ToArray(); 
     } 
    } 

    private List<DNComponent> components; 
    private string cachedDN; 

    public DistinguishedName(string distinguishedName) 
    { 
     cachedDN = distinguishedName; 
     components = new List<DNComponent>(); 
     foreach (KeyValuePair<string, string> kvp in Win32LDAP.ParseDN(distinguishedName)) 
     { 
      components.Add(new DNComponent(kvp.Key, kvp.Value, true)); 
     } 
    } 

    public DistinguishedName(IEnumerable<DNComponent> dnComponents) 
    { 
     components = new List<DNComponent>(dnComponents); 
     cachedDN = GetWholePath(","); 
    } 

    public bool Contains(DNComponent dnComponent) 
    { 
     return components.Contains(dnComponent); 
    } 

    public string GetDNSDomainName() 
    { 
     List<string> dcs = new List<string>(); 
     foreach (DNComponent dnc in components) 
     { 
      if(dnc.Type.Equals("DC", StringComparison.CurrentCultureIgnoreCase)) 
      { 
       dcs.Add(dnc.UnescapedValue); 
      } 
     } 
     return string.Join(".", dcs.ToArray()); 
    } 

    public string GetDomainDN() 
    { 
     List<string> dcs = new List<string>(); 
     foreach (DNComponent dnc in components) 
     { 
      if(dnc.Type.Equals("DC", StringComparison.CurrentCultureIgnoreCase)) 
      { 
       dcs.Add(dnc.WholeComponent); 
      } 
     } 
     return string.Join(",", dcs.ToArray()); 
    } 

    public string GetWholePath() 
    { 
     return GetWholePath(","); 
    } 

    public string GetWholePath(string separator) 
    { 
     List<string> parts = new List<string>(); 
     foreach (DNComponent component in components) 
     { 
      parts.Add(component.WholeComponent); 
     } 
     return string.Join(separator, parts.ToArray()); 
    } 

    public DistinguishedName GetParent() 
    { 
     if(components.Count == 1) 
     { 
      return null; 
     } 
     List<DNComponent> tempList = new List<DNComponent>(components); 
     tempList.RemoveAt(0); 
     return new DistinguishedName(tempList); 
    } 

    public override bool Equals(object obj) 
    { 
     if(obj is DistinguishedName) 
     { 
      DistinguishedName objDN = (DistinguishedName)obj; 
      if (this.Components.Length == objDN.Components.Length) 
      { 
       for (int i = 0; i < this.Components.Length; i++) 
       { 
        if (!this.Components[i].Equals(objDN.Components[i])) 
        { 
         return false; 
        } 
       } 
       return true; 
      } 
      return false; 
     } 
     return base.Equals(obj); 
    } 

    public override int GetHashCode() 
    { 
     return cachedDN.GetHashCode(); 
    } 
} 
1

Ecco due esempi di come è possibile ottenere i risultati che stai cercando

var MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com"; 

Questo si vedrebbe un elenco dei valori separati, ma avrebbe DC solo un'idea a mostrare che la divisione con String funziona`

var split = MyString.Split(new string[] { "OU=", "," }, StringSplitOptions.RemoveEmptyEntries); 

Questo si dividerà e si restituire solo i 3 elementi in un elenco in modo che se non si basano su un conteggio è possibile verificare visivamente che restituisce i 3 livelli di `UO =` `

var lstSplit = MyString.Split(new[] { ',' }) 
     .Where(splitItem => splitItem.StartsWith(
       "OU=", StringComparison.OrdinalIgnoreCase)).ToList(); 
3

questa estensione richiede meno risorse delle espressioni regualr.

public static int CountSubstring(this string text, string value) 
{     
    int count = 0, minIndex = text.IndexOf(value, 0); 
    while (minIndex != -1) 
    { 
     minIndex = text.IndexOf(value, minIndex + value.Length); 
     count++; 
    } 
    return count; 
} 

utilizzo:

MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com"; 
int count = MyString.CountSubstring("OU="); 
0
public static int CountOccurences(string needle, string haystack) 
{ 
    return (haystack.Length - haystack.Replace(needle, "").Length)/needle.Length; 
} 

Benchmarked contro altre risposte qui (quella regex e il "IndexOf" uno), funziona più velocemente.

+0

che è solo una copia di http://stackoverflow.com/questions/541954/how-would-you-count-occurrences-of-a-string-within-a-string aggiungi almeno un riferimento – fubo

Problemi correlati