2013-03-22 39 views
38

Giả sử tôi có một chuỗi như:Làm cách nào để đếm số lần xuất hiện chuỗi con?

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

sau đó tôi muốn biết có bao nhiêu thời gian xuất hiện của sub-string "OU =" trong chuỗi này. Với char duy nhất, có lẽ có cái gì đó như:

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

nhưng Split chỉ hoạt động cho char, không string.

Ngoài ra cách tìm vị trí của các lần xuất hiện n? Ví dụ, vị trí của số "OU=" trong chuỗi?

Cách giải quyết vấn đề này?

+1

'String.Split' có một số tình trạng quá tải cho phép bạn chia nhỏ theo chuỗi. Xem http://msdn.microsoft.com/en-us/library/tabh47cf.aspx Chia tách – shf301

+0

không chỉ hoạt động cho các ký tự ... – MUG4N

+0

Bạn có thể đã thực hiện việc này bằng cách sử dụng Nhiều Delim Tôi sẽ rất vui khi đăng bạn ví dụ được mã hóa đơn giản để sử dụng trong tương lai. 'và Split làm việc trên một chuỗi' 'Hãy nhớ rằng Split() trả về một mảng vì vậy trong trường hợp chuỗi nó sẽ trả về chuỗi [] bạn sẽ cần phải tạo chuỗi mới [] {" somestring "," someotherString "..vv ..} ' – MethodMan

Trả lời

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

Cảm ơn bạn. Ngoài ra làm thế nào để tìm vị trí của n lần xuất hiện? ví dụ, vị trí của lần thứ 2 "OU =" trong chuỗi? – KentZhou

+0

Ghé xung quanh một chút và tìm thấy câu hỏi này trên SO sẽ giúp bạn: http://stackoverflow.com/questions/767767/finding-multiple-indexes-from-source-string – tnw

+0

@KentZhou Bạn có nhớ chấp nhận câu trả lời của tôi nếu điều này không là giải pháp cho câu hỏi của bạn? – tnw

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

Không để thổi còi còi của riêng tôi , nhưng điều này phụ thuộc vào việc có sự tách biệt bằng dấu phẩy. Chắc chắn, nó hoạt động trong kịch bản rất cụ thể này, nhưng giải pháp Regex của tôi đơn giản và năng động hơn. – tnw

+0

Có, tôi đồng ý, chỉ cần thay thế. – Phil

+0

Tuyệt đối, tôi có thể đánh giá cao điều đó.+1 – tnw

2

dưới đây nên làm việc

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

Bạn có thể tìm thấy tất cả các lần xuất hiện và vị trí của họ với 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); 
} 

Bạn có thể nhận được kết quả tương tự từ một biểu thức chính quy:

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

Sự khác biệt chính:

  • Mã Regex ngắn
  • Mã Regex phân bổ một bộ sưu tập và nhiều chuỗi.
  • Mã IndexOf có thể được viết để xuất vị trí ngay lập tức mà không cần tạo bộ sưu tập.
  • Có khả năng mã Regex sẽ nhanh hơn trong sự cô lập, nhưng nếu được sử dụng nhiều lần tổng chi phí kết hợp của phân bổ chuỗi có thể gây ra tải cao hơn nhiều trên bộ thu gom rác.

Nếu tôi đã viết nội tuyến này, như một cái gì đó không được sử dụng thường xuyên, tôi có thể đi với giải pháp regex. Nếu tôi đặt nó vào một thư viện như một cái gì đó để được sử dụng rất nhiều, tôi có thể đi với giải pháp IndexOf.

+0

+1 ghi chú đẹp – tnw

+1

Lỗi đánh máy nhỏ? Danh sách vị trí = danh sách mới []; phải là Danh sách vị trí = danh sách mới (); – RickL

+0

Tôi tin rằng đây là một giải pháp tốt hơn. Nếu chuỗi bạn đang cố gắng so khớp giống như .s thì regex sẽ trả lại số không chính xác. Với vòng lặp while được đề xuất bởi Jim, hãy đếm chính xác số. – ashlar64

5

(Clippy-mode: ON)

Bạn trông giống như bạn đang phân tích một truy vấn LDAP!

Bạn có muốn phân tích nó:

  • cách thủ công? Goto "SplittingAndParsing"
  • Tự động qua các cuộc gọi Win32?Goto "Sử dụng Win32 qua 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)); 

"Sử dụng Win32 qua PInvoke":

Cách sử dụng:

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

Utility Mã số:

// 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

Dưới đây là hai ví dụ về cách bạn có thể nhận được kết quả mà bạn đang tìm kiếm

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

Cái này bạn sẽ thấy một danh sách các giá trị tách biệt nhưng nó sẽ có DC chỉ là một ý tưởng để cho thấy rằng việc chia tách với chuỗi không hoạt động`

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

Cái này sẽ Tách và gửi lại bạn chỉ có 3 mục vào một danh sách do đó nếu bạn không dựa vào một số bạn trực quan có thể xác nhận rằng nó trả về 3 cấp độ của `OU =` '

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

tiện ích mở rộng này cần ít tài nguyên hơn biểu thức 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; 
} 

sử dụng:

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 nó chống lại câu trả lời khác ở đây (một regex và "IndexOf" một), hoạt động nhanh hơn.

+0

đó chỉ là một bản sao của http://stackoverflow.com/questions/541954/how-would-you-count-occurrences-of-a-string-within-a-string thêm ít nhất một tham chiếu – fubo

Các vấn đề liên quan