tomaszkubacki
tomaszkubacki

Reputation: 3262

what is the fastest way to check whether string has uppercase letter in c#?

My first implementation idea is to do simply:

bool hasUpperCase (string str) {
    if(string.IsNullOrEmpty(str))
         return false;
    for (int i = 0; i < str.Length; i++) {
        if (char.IsUpper (str[i]))
            return true;                    
    }
    return false;
}

but maybe there is another faster way to do that ?

Upvotes: 23

Views: 24763

Answers (6)

Robert Achmann
Robert Achmann

Reputation: 2035

ok - time for the new truth!

This was a test for any upper case character in a string.

The string was guaranteed to not have any upper case character within the first 60K of characters. (I created the string from random.org)

I prevented string substitution optimization in the compiler by randomizing which 64K character string was passed to the test function.

All timings were very strictly around the actual test, and did not include function calling time.

I ran the test once, 10 times, and again for 10,000 times and averaged each set of the timings for each test.

I ran the test on a 64bit Win 7 with i3-2100 CPU @ 3.1 Ghz

Test Case 1:

   static bool testCaseOne(string str, out double ms)
    {
        bool result = false;
        DateTime start = DateTime.Now;

        result = !string.IsNullOrEmpty(str) && str.Any(c => char.IsUpper(c));
        ms = (DateTime.Now - start).TotalMilliseconds;
        return result;
    }

Resulting average time:

  1. 1 X = 3.000 ms
  2. 10 x = 0.860 ms
  3. 10,000 x = 0.821 ms

Test Case 2:

    static bool testCaseTwo(string str, out double ms)
    {
        bool result = false;
        DateTime start = DateTime.Now;

        if (string.IsNullOrEmpty(str))
        {
            ms = 0;
            return false;
        }
        result = Regex.IsMatch(str, "[A-Z]");

        ms = (DateTime.Now - start).TotalMilliseconds;

        return result;
    }

Resulting average time:

  1. 1 x = 2.000 ms
  2. 10 x = 1.597 ms
  3. 10,000 x = 1.603 ms

Test Case 3:

   static bool testCaseThree(string str, out double ms)
    {
        bool result = false;
        DateTime start = DateTime.Now;

        if (string.IsNullOrEmpty(str))
        {
            ms = 0;
            return false;
        }
        for (int i = 0; i < str.Length; i++)
        {
            if (char.IsUpper(str[i]))
            {
                result = true;
                break;
            }
        }
        ms = (DateTime.Now - start).TotalMilliseconds;
        return result;
    }

Resulting average time:

  1. 1 x = 1.000 ms
  2. 10 x = 0.357 ms
  3. 10,000 x = 0.298 ms

Test Case 4:

    static bool testCaseFour(string str, out double ms)
    {
        bool result = false;
        DateTime start = DateTime.Now;

        if (string.IsNullOrEmpty(str))
        {
            ms = 0;
            return false;
        }
        for (int i = 0; i < str.Length; i++)
        {

            if (str[i] > 64 && str[i] < 91)
            {
                result = true;
                break;
            }
        }
        ms = (DateTime.Now - start).TotalMilliseconds;
        return result;
    }

}

Resulting average time:

  1. 1 x = 0.000 ms
  2. 10 x = 0.137 ms
  3. 10,000 x = 0.184 ms

Interesting.

I hope this statisfies Mr. R. K. ;)

Upvotes: 5

Antho
Antho

Reputation: 191

    public static string Upper_To_Lower(string text)
    {
        if (Char.IsUpper(text[0]) == true) { text = text.Replace(text[0], char.ToLower(text[0])); return text; }

        return text;
    }

    public static string Lower_To_Upper(string text)
    {
        if (Char.IsLower(text[0]) == true) { text = text.Replace(text[0], char.ToUpper(text[0])); return text; }

        return text;
    }

Here i made 2 simple methods who check the first letter of any string and convert it from Upper to Lower and virse verca .... hope that will help you.

Upvotes: 0

user90150
user90150

Reputation:

The code looks fine to me, since you ask for performance, you can reduce the for loop from O(n) to O(n/2 + ~1) by adding the conditional checking from the reverse side.

Otherwise you can check two sub-sequent elements and increment the i by 2. Obviously you should check for i < str.Length for the second argument.

bool hasUpperCase (string str) {
if(string.IsNullOrEmpty(str))
     return false;
for (int i = 0; i < str.Length; i= i + 2) {
    if (char.IsUpper (str[i]))
        return true;                    

    if ((i + 1) < str.Length && char.IsUpper (str[i+1]))
        return true;                    
}
return false;

}

IMHO, this tip may help to answer algorithm interview, doesn't get much performance.

Upvotes: 2

aligray
aligray

Reputation: 2832

bool hasUpperCase(string str) {
    if (string.IsNullOrEmpty(str))
        return false;
    return Regex.IsMatch(str, "[A-Z]");
}

Disclaimer: I am no Regex expert but I tested this with the strings Testing, testinG, and tesTing, which all evaluated to true. However, it also evaluated to true with the string TESTING, which you may or may not want.

Upvotes: 3

Peter K.
Peter K.

Reputation: 8108

Cheating from here:

bool hasUpperCase (string str) {
 if(string.IsNullOrEmpty(str))
     return false;

  return str != str.ToLower();
}

Upvotes: 9

Femaref
Femaref

Reputation: 61437

You could reduce that to

bool HasUpperCase (string str) {
    return !string.IsNullOrEmpty(str) && str.Any(c => char.IsUpper(c));
}

using LINQ.

Upvotes: 40

Related Questions