获取C#字符串中第一个非空白字符的索引

有没有办法在C#中获取字符串中第一个非空白字符的索引(或更一般地说,第一个字符的索引匹配条件)而不编写我自己的循环代码?

编辑

通过“编写我自己的循环代码”,我真的意味着我正在寻找一个解决问题的紧凑表达式,而不会弄乱我正在处理的逻辑。

对于在这一点上的任何混淆,我道歉。

我喜欢定义自己的扩展方法,用于返回满足序列中自定义谓词的第一个元素的索引。

///  /// Returns the index of the first element in the sequence /// that satisfies a condition. ///  ///  /// The type of the elements of . ///  ///  /// An  that contains /// the elements to apply the predicate to. ///  ///  /// A function to test each element for a condition. ///  ///  /// The zero-based index position of the first element of  /// for which  returns ; /// or -1 if  is empty /// or no element satisfies the condition. ///  public static int IndexOf(this IEnumerable source, Func predicate) { int i = 0; foreach (TSource element in source) { if (predicate(element)) return i; i++; } return -1; } 

然后,您可以使用LINQ解决原始问题:

 string str = " Hello World"; int i = str.IndexOf(c => !char.IsWhiteSpace(c)); 

string当然是IEnumerable所以你可以使用Linq:

 int offset = someString.TakeWhile(c => char.IsWhiteSpace(c)).Count(); 
 string s= " \t Test"; Array.FindIndex(s.ToCharArray(), x => !char.IsWhiteSpace(x)); 

返回6

添加条件就是……

 Array.FindIndex(s.ToCharArray(), x => !char.IsWhiteSpace(x) && your condition); 
 var match = Regex.Match(" \t test ", @"\S"); // \S means all characters that are not whitespace if (match.Success) { int index = match.Index; //do something with index } else { //there were no non-whitespace characters, handle appropriately } 

如果您经常这样做,出于性能原因,您应该为这种模式缓存已编译的Regex ,例如:

 static readonly Regex nonWhitespace = new Regex(@"\S"); 

然后使用它像:

 nonWhitespace.Match(" \t test "); 

您可以使用String.IndexOfAny函数,该函数返回指定Unicode字符数组中第一个出现任何字符的字符。

或者,您可以使用String.TrimStart函数从字符串的开头删除所有空白字符。 第一个非空格字符的索引是原始字符串和修剪字符串的长度之间的差异。

你甚至可以选择一组字符来修剪:)

基本上,如果你正在寻找一组有限的字符(让我们说数字)你应该采用第一种方法。

如果您试图忽略一组有限的字符(如空格),则应使用第二种方法。

最后一种方法是使用Linq方法:

 string s = " qsdmlkqmlsdkm"; Console.WriteLine(s.TrimStart()); Console.WriteLine(s.Length - s.TrimStart().Length); Console.WriteLine(s.FirstOrDefault(c => !Char.IsWhiteSpace(c))); Console.WriteLine(s.IndexOf(s.FirstOrDefault(c => !Char.IsWhiteSpace(c)))); 

输出:

 qsdmlkqmlsdkm 8 q 8 

您可以修剪,获取第一个字符并使用IndexOf。

由于这里有几个解决方案,我决定做一些性能测试,看看每个解决方案的表现。 决定为那些感兴趣的人分享这些结果……

  int iterations = 1000000; int result = 0; string s= " \t Test"; System.Diagnostics.Stopwatch watch = new Stopwatch(); // Convert to char array and use FindIndex watch.Start(); for (int i = 0; i < iterations; i++) result = Array.FindIndex(s.ToCharArray(), x => !char.IsWhiteSpace(x)); watch.Stop(); Console.WriteLine("Convert to char array and use FindIndex: " + watch.ElapsedMilliseconds); // Trim spaces and get index of first character watch.Restart(); for (int i = 0; i < iterations; i++) result = s.IndexOf(s.TrimStart().Substring(0,1)); watch.Stop(); Console.WriteLine("Trim spaces and get index of first character: " + watch.ElapsedMilliseconds); // Use extension method watch.Restart(); for (int i = 0; i < iterations; i++) result = s.IndexOf(c => !char.IsWhiteSpace(c)); watch.Stop(); Console.WriteLine("Use extension method: " + watch.ElapsedMilliseconds); // Loop watch.Restart(); for (int i = 0; i < iterations; i++) { result = 0; foreach (char c in s) { if (!char.IsWhiteSpace(c)) break; result++; } } watch.Stop(); Console.WriteLine("Loop: " + watch.ElapsedMilliseconds); 

结果以毫秒为单位....

其中s =“\ t测试”
转换为char数组并使用FindIndex: 154
修剪空格并获取第一个字符的索引: 189
使用扩展方法: 234
循环: 146

其中s =“测试”
转换为char数组并使用FindIndex: 39
修剪空格并获取第一个字符的索引: 155
使用扩展方法: 57
循环: 15

其中s =(1000个字符串,没有空格)
转换为char数组并使用FindIndex: 506
修剪空格并获取第一个字符的索引: 534
使用扩展方法: 51
循环: 15

其中s =(1000个字符串以“\ t Test”开头)
转换为char数组并使用FindIndex: 609
修剪空格并获取第一个字符的索引: 1103
使用扩展方法: 226
循环: 146

得出你自己的结论,但我的结论是使用你最喜欢的那个,因为在现实世界的场景中,性能差异是微不足道的。

有一个非常简单的解决方案

 string test = " hello world"; int pos = test.ToList().FindIndex(x => char.IsWhiteSpace(x) == false); 

pos将是4

你可以有更复杂的条件,如:

 pos = test.ToList().FindIndex((x) => { if (x == 's') //Your complex conditions go here return true; else return false; } ); 

是的你可以试试这个:

 string stg = " xyz"; int indx = (stg.Length - stg.Trim().Length); 

有些东西会在某个地方循环。 为了完全控制什么是空白,你可以使用linq来对象进行循环:

 int index = Array.FindIndex( s.ToCharArray(), x => !(new [] { '\t', '\r', '\n', ' '}.Any(c => c == x))); 

这里有很多解决方案将字符串转换为数组。 这不是必需的,字符串中的单个字符可以像数组中的项一样被访问。

这是我应该非常有效的解决方案:

 private static int FirstNonMatch(string s, Func predicate, int startPosition = 0) { for (var i = startPosition; i < s.Length; i++) if (!predicate(s[i])) return i; return -1; } private static int LastNonMatch(string s, Func predicate, int startPosition) { for (var i = startPosition; i >= 0; i--) if (!predicate(s[i])) return i; return -1; } 

要使用这些,请执行以下操作:

 var x = FirstNonMatch(" asdf ", char.IsWhiteSpace); var y = LastNonMatch(" asdf ", char.IsWhiteSpace, " asdf ".Length);