查找第一个大写字符的索引
作为一个C#新手,目前要找出一个字符串中第一个大写字符的索引,我已经想出了办法
var pos = spam.IndexOf(spam.ToCharArray().First(s => String.Equals(s, char.ToUpper(s))));
从function上来说,代码工作正常,只是我有两次遍历字符串的不适,一次找到字符然后找到索引。 是否有可能使用LINQ在一次传递中获取第一个UpperCase字符的索引?
C ++中的等价方式就像是
std::string::const_iterator itL=find_if(spam.begin(), spam.end(),isupper);
一个等效的Python语法
next(i for i,e in enumerate(spam) if e.isupper())
好吧,如果你只是想在LINQ
做,你可以尝试使用类似的东西
(from ch in spam.ToArray() where Char.IsUpper(ch) select spam.IndexOf(ch))
如果你对字符串运行,比如说
"string spam = "abcdeFgihjklmnopQrstuv";"
结果将是: 5, 16
。
这将返回预期的结果。
这是基于@ Tigran的答案,但即使有重复,也会返回所有大写的索引:
from i in Enumerable.Range(0, searchText.Length - 1) where Char.IsUpper(searchText.Chars[i]) select i
仅仅因为我经常发现人们不知道:
选择有一种方法来获取索引以及您要枚举的项目。 虽然它会产生一些额外的开销,但你可以这样做:
var objectsWithCharAndIndex = myString.Select((c,i)=>new {Char = c,Index = i});
那么它唯一的问题是:
var firstCapitalIndex = objectsWithCharAndIndex.First(o => Char.IsUpper(o.Char)).Index;
或者全部归还
var allCapitalIndexes = objectsWithCharAndIndex.Where(o => Char.IsUpper(o.Char)).Select(o=>o.Index);
如果你需要char和索引,你可以迭代对象。
这只是普通的Linq语法,而不是Linq查询语法。
不需要LINQ:
int index = 0; foreach(Char c in myString) { if(Char.IsUpper(c)) break; index++; } // index now contains the index of the first upper case character
这可以很容易地转换为扩展方法,如@Tigran评论。
另一种可能性
string s = "0123aBc"; int rslt = -1; var ch = s.FirstOrDefault(c => char.IsUpper(c)); if (ch != 0) rslt = s.IndexOf(ch);
而且,如果你只关心英语:
char[] UpperCaseChars = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; int rslt = s.IndexOfAny(UpperCaseChars);
这可能会比其他任何一个执行得快得多,而且如果我这么做的话,我就会使用它。
另一种可能性是使用正则表达式:
var match = Regex.Match(s, "\p{Lu}", RegexOptions.None); int rslt = match.Success ? match.Index : -1;
这将匹配任何Unicode大写字符。 如果您只想要英语,请将表达式更改为"[AZ]"
。
Linq没有提供开箱即用的有效方法,但您可以非常轻松地扩展Linq以提供此function。
如果将此类添加到解决方案中:
internal static class EnumerableExtensions { public static int IndexOfNth(this IEnumerable enumerable, Func predicate, int skip = 0) { var index = 0; foreach (var value in enumerable) { if (predicate(value)) { if (skip-- == 0) return index; } index++; } return -1; } public static int IndexOfFirst (this IEnumerable enumerable, Func predicate) { return enumerable.IndexOfNth(predicate); } }
然后你可以编写这样有效的代码并且只枚举一次字符串:
var firstUpper = spam[spam.IndexOfFirst(Char.IsUpper)];
注意:如果字符串不包含任何大写字母,这会导致索引超出范围,因此您需要额外检查IndexOfFirst
返回-1
。
通过此实现,您还可以找到第二个大写字母,如下所示:
var secondUpper = spam[spam.IndexOfNth(Char.IsUpper, 1)];
例如,它适用于任何可枚举的chars枚举
var indexOfFirstManager = employees.IndexOfFirst(employee => employee.IsManager);