如何计算子string的发生?

假设我有一个string:

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

那么我想知道这个string中子string“OU =”的出现次数。 用一个字符,也许有这样的东西:

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

Split只适用于char ,而不是string

另外如何findn次出现的位置? 例如,第二个"OU="在string中的位置?

如何解决这个问题?

 Regex.Matches(input, "OU=").Count 

你可以用IndexOffind所有的事件和他们的位置:

 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); } 

你可以从正则expression式得到相同的结果:

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

主要区别:

  • 正则expression式代码更短
  • 正则expression式代码分配一个集合和多个string。
  • 可以写入IndexOf代码以立即输出位置,而不创build集合。
  • 很可能正则expression式代码的隔离速度会更快,但是如果多次使用string分配的组合开销,可能会在垃圾收集器上造成更高的负载。

如果我正在写这个内联,作为一个没有经常使用的东西,我可能会去正则expression式的解决scheme。 如果我把它放到一个图书馆当中,那么我可能会使用IndexOf解决scheme。

(Clippy-mode: ON

你看起来像你parsing一个LDAP查询!

你想parsing它:

  • 手动? 转到“分割和分割”
  • 自动通过Win32调用? 转到“通过PInvoke使用Win32”

(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)); 

“通过PInvoke使用Win32”:

用法:

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

工具代码:

 // 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(); } } 
 int count = myString.Split(new []{','}) .Count(item => item.StartsWith( "OU=", StringComparison.OrdinalIgnoreCase)) 

下面应该工作

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

这个扩展需要比常规expression式更less的资源。

 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; } 

用法:

 MyString = "OU=Level3,OU=Level2,OU=Level1,DC=domain,DC=com"; int count = MyString.CountSubstring("OU="); 

以下是您如何获得所需结果的两个示例

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

这一个你会看到一个值的列表分隔,但它会有DC只是一个想法,表明与string的分割确实工作

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

这一个将拆分和返回你只有3个项目成一个列表,这样,如果你不依靠一个计数,你可以直观地validation,它返回的OU =“

 var lstSplit = MyString.Split(new[] { ',' }) .Where(splitItem => splitItem.StartsWith( "OU=", StringComparison.OrdinalIgnoreCase)).ToList(); 
 public static int CountOccurences(string needle, string haystack) { return (haystack.Length - haystack.Replace(needle, "").Length) / needle.Length; } 

对照这里的其他答案(正则expression式和“IndexOf”之一)进行基准testing,速度更快。