查找第一个大写字符的索引

时间:2012-04-21 09:21:54

标签: c# string linq search

作为一个C#新手,目前要找出一个字符串中第一个大写字符的索引我已经找到了一种方法

var pos = spam.IndexOf(spam.ToCharArray().First(s => String.Equals(s, char.ToUpper(s))));

从功能上来说,代码工作正常,只是我有两次遍历字符串的不适,一次找到字符然后找到索引。是否有可能使用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())

7 个答案:

答案 0 :(得分:6)

好吧,如果您只是希望LINQ中执行此操作,您可以尝试使用类似

的内容
(from ch in spam.ToArray() where Char.IsUpper(ch) 
         select spam.IndexOf(ch))

如果你对字符串运行,请说

"string spam = "abcdeFgihjklmnopQrstuv";"

结果将是:5, 16

这将返回预期结果。

答案 1 :(得分:2)

这是基于@ Tigran的答案,但即使有重复项,也会返回所有大写的索引:

from i in Enumerable.Range(0, searchText.Length - 1) 
      where Char.IsUpper(searchText.Chars[i]) select i

答案 2 :(得分:2)

因为我经常发现人们不知道:

选择有一种方法可以获取索引以及您要枚举的项目。 虽然它会产生一些额外的开销,但你可以这样做:

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查询语法。

答案 3 :(得分:1)

不需要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评论。

答案 4 :(得分:0)

另一种可能性:

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大写字符。如果您只想要英语,请将表达式更改为"[A-Z]"

答案 5 :(得分:0)

Linq没有提供开箱即用的有效方法,但您可以非常轻松地扩展Linq以提供此功能。

如果您将此类添加到解决方案中:

internal static class EnumerableExtensions
{
    public static int IndexOfNth<T>(this IEnumerable<T> enumerable, Func<T, bool> 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<T>(this IEnumerable<T> enumerable, Func<T, bool> 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);

答案 6 :(得分:0)

String.Concat(
  str.Select(c => Char.IsUpper(c) ? $" {c}" : $"{c}")
);