Find Index of the First Uppercase character

﹥>﹥吖頭↗ 提交于 2019-12-14 01:38:00

问题


As a C# Novice, currently to find out the index of the first uppercase character in a string I have figured out a way

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

Functionally the code works fine except that I was having the discomfort of traversing the string twice, once to find the Character and then the Index. Is there any possibility to get the index of the first UpperCase character in one pass using LINQ?

an equivalent way in C++ would be something like

std::string::const_iterator itL=find_if(spam.begin(), spam.end(),isupper);

an equivalent Python Syntax would be

next(i for i,e in enumerate(spam) if e.isupper())

回答1:


Well, if you just want to do it in LINQ, you can try to use something like

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

If you run this against string, say

"string spam = "abcdeFgihjklmnopQrstuv";"

the result would be: 5, 16.

This will return expected result.




回答2:


Here is an answer based on @Tigran's but that will return the index of all capitals, even if there are duplicates:

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



回答3:


Just because i often find people dont know:

Select has a way to get the index aswell as the item you are enumerating. Eventhough it gives a slight extra overhead you could do this:

var objectsWithCharAndIndex = myString.Select((c,i)=>new {Char = c,Index = i});

then its only a matter of doing:

var firstCapitalIndex = objectsWithCharAndIndex.First(o => Char.IsUpper(o.Char)).Index;

or return them all

var allCapitalIndexes = objectsWithCharAndIndex.Where(o => Char.IsUpper(o.Char)).Select(o=>o.Index);

of you could iterate through the objects if you need the char and the index together.

This is just normal Linq syntax, not Linq query syntax.




回答4:


No need for 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

This can be easily converted to an extension method, as @Tigran comments.




回答5:


Another possibility:

string s = "0123aBc";
int rslt = -1;
var ch = s.FirstOrDefault(c => char.IsUpper(c));
if (ch != 0)
    rslt = s.IndexOf(ch);

And, if you're only concerned with English:

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

That's probably going to execute a lot faster than any of the others, and is what I'd use if I were doing this a lot.

Another possibility is to use a regular expression:

var match = Regex.Match(s, "\p{Lu}", RegexOptions.None);
int rslt = match.Success ? match.Index : -1;

That'll match any Unicode upper case character. If you want just English, change the expression to "[A-Z]".




回答6:


Linq does not provide an efficient way of doing this out of the box, but you can extend Linq to provide this capability very easily.

If you add this class to your solution:

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

Then you can write code like this that will be efficient and only enumerate the string once:

var firstUpper = spam[spam.IndexOfFirst(Char.IsUpper)];

Note: this blows up with index out of bounds if the string does not contain any upper case letters so you would need an extra check for IndexOfFirst returning -1.

With this implementation you can also find the 2nd upper case letter like this:

var secondUpper = spam[spam.IndexOfNth(Char.IsUpper, 1)];

And it works with any enumerable not just enumerations of chars, for example

var indexOfFirstManager = employees.IndexOfFirst(employee => employee.IsManager);



回答7:


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


来源:https://stackoverflow.com/questions/10257711/find-index-of-the-first-uppercase-character

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!