在C#中确定未修剪字符串是否为空的最有效方法是什么?

时间:2022-12-19 07:23:26

I have a string that may have whitespace characters around it and I want to check to see whether it is essentially empty.

我有一个字符串,周围可能有空格字符,我想检查它是否基本上是空的。

There are quite a few ways to do this:

有很多方法可以做到这一点:

1  if (myString.Trim().Length == 0)
2  if (myString.Trim() == "")
3  if (myString.Trim().Equals(""))
4  if (myString.Trim() == String.Empty)
5  if (myString.Trim().Equals(String.Empty))

I'm aware that this would usually be a clear case of premature optimization, but I'm curious and there's a chance that this will be done enough to have a performance impact.

我知道这通常是一个过早优化的明显案例,但我很好奇,并且有可能做到这一点足以产生性能影响。

So which of these is the most efficient method?

那么这些中最有效的方法是哪一种?

Are there any better methods I haven't thought of?

有没有更好的方法我没想过?


Edit: Notes for visitors to this question:

编辑:此问题的访问者注意事项:

  1. There have been some amazingly detailed investigations into this question - particularly from Andy and Jon Skeet.

    对这个问题进行了一些非常详细的调查 - 特别是来自Andy和Jon Skeet。

  2. If you've stumbled across the question while searching for something, it's well worth your while reading at least Andy's and Jon's posts in their entirety.

    如果你在搜索某些内容时偶然发现了这个问题,那么至少阅读Andy和Jon的帖子是非常值得的。

It seems that there are a few very efficient methods and the most efficient depends on the contents of the strings I need to deal with.

似乎有一些非常有效的方法,最有效的方法取决于我需要处理的字符串的内容。

If I can't predict the strings (which I can't in my case), Jon's IsEmptyOrWhiteSpace methods seem to be faster generally.

如果我无法预测字符串(在我的情况下我无法预测),Jon的IsEmptyOrWhiteSpace方法通常会更快。

Thanks all for your input. I'm going to select Andy's answer as the "correct" one simply because he deserves the reputation boost for the effort he put in and Jon has like eleventy-billion reputation already.

谢谢大家的意见。我将选择安迪的答案作为“正确”的答案仅仅是因为他应该为他所付出的努力赢得声誉,而Jon已经拥有了十亿美元的声誉。

8 个解决方案

#1


Edit: New tests:

编辑:新测试:

Test orders:
x. Test name
Ticks: xxxxx //Empty String
Ticks: xxxxx //two space
Ticks: xxxxx //single letter
Ticks: xxxxx //single letter with space
Ticks: xxxxx //long string
Ticks: xxxxx //long string  with space

1. if (myString.Trim().Length == 0)
ticks: 4121800
ticks: 7523992
ticks: 17655496
ticks: 29312608
ticks: 17302880
ticks: 38160224

2.  if (myString.Trim() == "")
ticks: 4862312
ticks: 8436560
ticks: 21833776
ticks: 32822200
ticks: 21655224
ticks: 42358016


3.  if (myString.Trim().Equals(""))
ticks: 5358744
ticks: 9336728
ticks: 18807512
ticks: 30340392
ticks: 18598608
ticks: 39978008


4.  if (myString.Trim() == String.Empty)
ticks: 4848368
ticks: 8306312
ticks: 21552736
ticks: 32081168
ticks: 21486048
ticks: 41667608


5.  if (myString.Trim().Equals(String.Empty))
ticks: 5372720
ticks: 9263696
ticks: 18677728
ticks: 29634320
ticks: 18551904
ticks: 40183768


6.  if (IsEmptyOrWhitespace(myString))  //See John Skeet's Post for algorithm
ticks: 6597776
ticks: 9988304
ticks: 7855664
ticks: 7826296
ticks: 7885200
ticks: 7872776

7. is (string.IsNullOrEmpty(myString.Trim())  //Cloud's suggestion
ticks: 4302232
ticks: 10200344
ticks: 18425416
ticks: 29490544
ticks: 17800136
ticks: 38161368

And the code used:

并使用的代码:

public void Main()
{

    string res = string.Empty;

    for (int j = 0; j <= 5; j++) {

        string myString = "";

        switch (j) {

            case 0:
                myString = "";
                break;
            case 1:
                myString = "  ";
                break;
            case 2:
                myString = "x";
                break;
            case 3:
                myString = "x ";
                break;
            case 4:
                myString = "this is a long string for testing triming empty things.";
                break;
            case 5:
                myString = "this is a long string for testing triming empty things. ";

                break;
        }

        bool result = false;
        Stopwatch sw = new Stopwatch();

        sw.Start();
        for (int i = 0; i <= 100000; i++) {


            result = myString.Trim().Length == 0;
        }
        sw.Stop();


        res += "ticks: " + sw.ElapsedTicks + Environment.NewLine;
    }


    Console.ReadKey();  //break point here to get the results
}

#2


(EDIT: See bottom of post for benchmarks on different micro-optimizations of the method)

(编辑:有关该方法的不同微优化的基准,请参见帖子的底部)

Don't trim it - that might create a new string which you don't actually need. Instead, look through the string for any characters that aren't whitespace (for whatever definition you want). For example:

不要修剪它 - 这可能会创建一个你实际上并不需要的新字符串。相反,请查看字符串中是否有任何不是空格的字符(无论您想要什么样的定义)。例如:

public static bool IsEmptyOrWhitespace(string text)
{
    // Avoid creating iterator for trivial case
    if (text.Length == 0)
    {
        return true;
    }
    foreach (char c in text)
    {
        // Could use Char.IsWhiteSpace(c) instead
        if (c==' ' || c=='\t' || c=='\r' || c=='\n')
        {
            continue;
        }
        return false;
    }
    return true;
}

You might also consider what you want the method to do if text is null.

如果text为null,您可能还会考虑您希望该方法执行的操作。

Possible further micro-optimizations to experiment with:

可能进一步微观优化以进行试验:

  • Is foreach faster or slower than using a for loop like the one below? Note that with the for loop you can remove the "if (text.Length==0)" test at the start.

    foreach比使用下面的for循环更快还是更慢?请注意,使用for循环,您可以在开始时删除“if(text.Length == 0)”测试。

    for (int i = 0; i < text.Length; i++)
    {
        char c = text[i];
        // ...
    
  • Same as above, but hoisting the Length call. Note that this isn't good for normal arrays, but might be useful for strings. I haven't tested it.

    与上面相同,但是提升长度呼叫。请注意,这对于普通数组来说并不好,但可能对字符串很有用。我没有测试过。

    int length = text.Length;
    for (int i = 0; i < length; i++)
    {
        char c = text[i];
    
  • In the body of the loop, is there any difference (in speed) between what we've got and:

    在循环体中,我们得到的和之间有什么不同(速度):

    if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
    {
        return false;
    }
    
  • Would a switch/case be faster?

    开关/箱子会更快吗?

    switch (c)
    {
        case ' ': case '\r': case '\n': case '\t':
            return false;               
    }
    

Update on Trim behaviour

更新修剪行为

I've just been looking into how Trim can be as efficient as this. It seems that Trim will only create a new string if it needs to. If it can return this or "" it will:

我一直在研究Trim如何像这样高效。似乎Trim只会在需要时创建一个新字符串。如果它可以返回这个或“”它将:

using System;

class Test
{
    static void Main()
    {
        CheckTrim(string.Copy(""));
        CheckTrim("  ");
        CheckTrim(" x ");
        CheckTrim("xx");
    }

    static void CheckTrim(string text)
    {
        string trimmed = text.Trim();
        Console.WriteLine ("Text: '{0}'", text);
        Console.WriteLine ("Trimmed ref == text? {0}",
                          object.ReferenceEquals(text, trimmed));
        Console.WriteLine ("Trimmed ref == \"\"? {0}",
                          object.ReferenceEquals("", trimmed));
        Console.WriteLine();
    }
}

This means it's really important that any benchmarks in this question should use a mixture of data:

这意味着这个问题中的任何基准都应该使用混合数据,这一点非常重要:

  • Empty string
  • Whitespace
  • Whitespace surrounding text
  • 围绕文字的空白

  • Text without whitespace
  • 没有空格的文本

Of course, the "real world" balance between these four is impossible to predict...

当然,这四者之间的“现实世界”平衡是无法预测的......

Benchmarks I've run some benchmarks of the original suggestions vs mine, and mine appears to win in everything I throw at it, which surprises me given the results in other answers. However, I've also benchmarked the difference between foreach, for using text.Length, for using text.Length once and then reversing the iteration order, and for with a hoisted length.

基准我已经对我的原始建议进行了一些基准测试,并且我的投入似乎在我投入的所有内容中获胜,这让我感到惊讶,因为其他答案的结果。但是,我还使用text.Length,使用text.Length,然后反转迭代顺序,以及使用提升的长度,对foreach之间的差异进行基准测试。

Basically the for loop is very slightly faster, but hoisting the length check makes it slower than foreach. Reversing the for loop direction is very slightly slower than foreach too. I strongly suspect that the JIT is doing interesting things here, in terms of removing duplicate bounds checks etc.

基本上for循环非常快,但提升长度检查使它比foreach慢。反转for循环方向也比foreach慢一点。我强烈怀疑JIT在这里做了一些有趣的事情,包括删除重复的边界检查等。

Code: (see my benchmarking blog entry for the framework this is written against)

代码:(请参阅我的基准博客条目,该框架针对此编写)

using System;
using BenchmarkHelper;

public class TrimStrings
{
    static void Main()
    {
        Test("");
        Test(" ");
        Test(" x ");
        Test("x");
        Test(new string('x', 1000));
        Test(" " + new string('x', 1000) + " ");
        Test(new string(' ', 1000));
    }

    static void Test(string text)
    {
        bool expectedResult = text.Trim().Length == 0;
        string title = string.Format("Length={0}, result={1}", text.Length, 
                                     expectedResult);

        var results = TestSuite.Create(title, text, expectedResult)
/*            .Add(x => x.Trim().Length == 0, "Trim().Length == 0")
            .Add(x => x.Trim() == "", "Trim() == \"\"")
            .Add(x => x.Trim().Equals(""), "Trim().Equals(\"\")")
            .Add(x => x.Trim() == string.Empty, "Trim() == string.Empty")
            .Add(x => x.Trim().Equals(string.Empty), "Trim().Equals(string.Empty)")
*/
            .Add(OriginalIsEmptyOrWhitespace)
            .Add(IsEmptyOrWhitespaceForLoop)
            .Add(IsEmptyOrWhitespaceForLoopReversed)
            .Add(IsEmptyOrWhitespaceForLoopHoistedLength)
            .RunTests()                          
            .ScaleByBest(ScalingMode.VaryDuration);

        results.Display(ResultColumns.NameAndDuration | ResultColumns.Score,
                        results.FindBest());
    }

    public static bool OriginalIsEmptyOrWhitespace(string text)
    {
        if (text.Length == 0)
        {
            return true;
        }
        foreach (char c in text)
        {
            if (c==' ' || c=='\t' || c=='\r' || c=='\n')
            {
                continue;
            }
            return false;
        }
        return true;
    }

    public static bool IsEmptyOrWhitespaceForLoop(string text)
    {
        for (int i=0; i < text.Length; i++)
        {
            char c = text[i];
            if (c==' ' || c=='\t' || c=='\r' || c=='\n')
            {
                continue;
            }
            return false;
        }
        return true;
    }

    public static bool IsEmptyOrWhitespaceForLoopReversed(string text)
    {
        for (int i=text.Length-1; i >= 0; i--)
        {
            char c = text[i];
            if (c==' ' || c=='\t' || c=='\r' || c=='\n')
            {
                continue;
            }
            return false;
        }
        return true;
    }

    public static bool IsEmptyOrWhitespaceForLoopHoistedLength(string text)
    {
        int length = text.Length;
        for (int i=0; i < length; i++)
        {
            char c = text[i];
            if (c==' ' || c=='\t' || c=='\r' || c=='\n')
            {
                continue;
            }
            return false;
        }
        return true;
    }
}

Results:

============ Length=0, result=True ============
OriginalIsEmptyOrWhitespace             30.012 1.00
IsEmptyOrWhitespaceForLoop              30.802 1.03
IsEmptyOrWhitespaceForLoopReversed      32.944 1.10
IsEmptyOrWhitespaceForLoopHoistedLength 35.113 1.17

============ Length=1, result=True ============
OriginalIsEmptyOrWhitespace             31.150 1.04
IsEmptyOrWhitespaceForLoop              30.051 1.00
IsEmptyOrWhitespaceForLoopReversed      31.602 1.05
IsEmptyOrWhitespaceForLoopHoistedLength 33.383 1.11

============ Length=3, result=False ============
OriginalIsEmptyOrWhitespace             30.221 1.00
IsEmptyOrWhitespaceForLoop              30.131 1.00
IsEmptyOrWhitespaceForLoopReversed      34.502 1.15
IsEmptyOrWhitespaceForLoopHoistedLength 35.690 1.18

============ Length=1, result=False ============
OriginalIsEmptyOrWhitespace             31.626 1.05
IsEmptyOrWhitespaceForLoop              30.005 1.00
IsEmptyOrWhitespaceForLoopReversed      32.383 1.08
IsEmptyOrWhitespaceForLoopHoistedLength 33.666 1.12

============ Length=1000, result=False ============
OriginalIsEmptyOrWhitespace             30.177 1.00
IsEmptyOrWhitespaceForLoop              33.207 1.10
IsEmptyOrWhitespaceForLoopReversed      30.867 1.02
IsEmptyOrWhitespaceForLoopHoistedLength 31.837 1.06

============ Length=1002, result=False ============
OriginalIsEmptyOrWhitespace             30.217 1.01
IsEmptyOrWhitespaceForLoop              30.026 1.00
IsEmptyOrWhitespaceForLoopReversed      34.162 1.14
IsEmptyOrWhitespaceForLoopHoistedLength 34.860 1.16

============ Length=1000, result=True ============
OriginalIsEmptyOrWhitespace             30.303 1.01
IsEmptyOrWhitespaceForLoop              30.018 1.00
IsEmptyOrWhitespaceForLoopReversed      35.475 1.18
IsEmptyOrWhitespaceForLoopHoistedLength 40.927 1.36

#3


I really don't know which is faster; although my gut feeling says number one. But here's another method:

我真的不知道哪个更快;虽然我的直觉是第一名。但这是另一种方法:

if (String.IsNullOrEmpty(myString.Trim()))

#4


myString.Trim().Length == 0 Took : 421 ms

myString.Trim()。Length == 0 Took:421 ms

myString.Trim() == '' took : 468 ms

myString.Trim()==''花了:468毫秒

if (myString.Trim().Equals("")) Took : 515 ms

if(myString.Trim()。Equals(“”)):515 ms

if (myString.Trim() == String.Empty) Took : 484 ms

if(myString.Trim()== String.Empty)Took:484 ms

if (myString.Trim().Equals(String.Empty)) Took : 500 ms

if(myString.Trim()。Equals(String.Empty))Took:500 ms

if (string.IsNullOrEmpty(myString.Trim())) Took : 437 ms

if(string.IsNullOrEmpty(myString.Trim()))Took:437 ms

In my tests, it looks like myString.Trim().Length == 0 and surprisingly, string.IsNullOrEmpty(myString.Trim()) were consistently the fastest. The results above are a typical result from doing 10,000,000 comparisons.

在我的测试中,它看起来像myString.Trim()。Length == 0并且令人惊讶的是,string.IsNullOrEmpty(myString.Trim())始终是最快的。上述结果是进行10,000,000次比较的典型结果。

#5


Checking the length of a string for being zero is the most efficient way to test for an empty string, so I would say number 1:

检查字符串的长度为零是测试空字符串的最有效方法,所以我想说数字1:

if (myString.Trim().Length == 0)

The only way to optimize this further might be to avoid trimming by using a compiled regular expression (Edit: this is actually much slower than using Trim().Length).

进一步优化这种方法的唯一方法可能是避免使用编译的正则表达式进行修剪(编辑:这实际上比使用Trim()慢得多。长度)。

Edit: The suggestion to use Length came from a FxCop guideline. I've also just tested it: it's 2-3 times faster than comparing to an empty string. However both approaches are still extremely fast (we're talking nanoseconds) - so it hardly matters which one you use. Trimming is so much more of a bottleneck it's hundreds of times slower than the actual comparison at the end.

编辑:使用Length的建议来自FxCop指南。我也刚刚对它进行了测试:它比空字符串快2-3倍。然而,这两种方法仍然非常快(我们说的是纳秒) - 所以你使用哪种方法几乎不重要。修剪是一个瓶颈,它比最后的实际比较慢几百倍。

#6


String.IsNullOrWhitespace in .NET 4 Beta 2 also plays in this space and doesnt need to be custom written

.NET 4 Beta 2中的String.IsNullOrWhitespace也在这个空间中播放,不需要自定义编写

#7


Since I just started I can't comment so here it is.

自从我刚开始以来,我不能发表评论,所以在这里。

if (String.IsNullOrEmpty(myString.Trim()))

Trim() call will fail if myString is null since you can't call methods in a object that is null (NullReferenceException).

如果myString为null,则Trim()调用将失败,因为您无法调用null(NullReferenceException)对象中的方法。

So the correct syntax would be something like this:

所以正确的语法是这样的:

if (!String.IsNullOrEmpty(myString))
{
    string trimmedString = myString.Trim();
    //do the rest of you code
}
else
{
    //string is null or empty, don't bother processing it
}

#8


public static bool IsNullOrEmpty(this String str, bool checkTrimmed)
{
  var b = String.IsNullOrEmpty(str);
  return checkTrimmed ? b && str.Trim().Length == 0 : b;
}

#1


Edit: New tests:

编辑:新测试:

Test orders:
x. Test name
Ticks: xxxxx //Empty String
Ticks: xxxxx //two space
Ticks: xxxxx //single letter
Ticks: xxxxx //single letter with space
Ticks: xxxxx //long string
Ticks: xxxxx //long string  with space

1. if (myString.Trim().Length == 0)
ticks: 4121800
ticks: 7523992
ticks: 17655496
ticks: 29312608
ticks: 17302880
ticks: 38160224

2.  if (myString.Trim() == "")
ticks: 4862312
ticks: 8436560
ticks: 21833776
ticks: 32822200
ticks: 21655224
ticks: 42358016


3.  if (myString.Trim().Equals(""))
ticks: 5358744
ticks: 9336728
ticks: 18807512
ticks: 30340392
ticks: 18598608
ticks: 39978008


4.  if (myString.Trim() == String.Empty)
ticks: 4848368
ticks: 8306312
ticks: 21552736
ticks: 32081168
ticks: 21486048
ticks: 41667608


5.  if (myString.Trim().Equals(String.Empty))
ticks: 5372720
ticks: 9263696
ticks: 18677728
ticks: 29634320
ticks: 18551904
ticks: 40183768


6.  if (IsEmptyOrWhitespace(myString))  //See John Skeet's Post for algorithm
ticks: 6597776
ticks: 9988304
ticks: 7855664
ticks: 7826296
ticks: 7885200
ticks: 7872776

7. is (string.IsNullOrEmpty(myString.Trim())  //Cloud's suggestion
ticks: 4302232
ticks: 10200344
ticks: 18425416
ticks: 29490544
ticks: 17800136
ticks: 38161368

And the code used:

并使用的代码:

public void Main()
{

    string res = string.Empty;

    for (int j = 0; j <= 5; j++) {

        string myString = "";

        switch (j) {

            case 0:
                myString = "";
                break;
            case 1:
                myString = "  ";
                break;
            case 2:
                myString = "x";
                break;
            case 3:
                myString = "x ";
                break;
            case 4:
                myString = "this is a long string for testing triming empty things.";
                break;
            case 5:
                myString = "this is a long string for testing triming empty things. ";

                break;
        }

        bool result = false;
        Stopwatch sw = new Stopwatch();

        sw.Start();
        for (int i = 0; i <= 100000; i++) {


            result = myString.Trim().Length == 0;
        }
        sw.Stop();


        res += "ticks: " + sw.ElapsedTicks + Environment.NewLine;
    }


    Console.ReadKey();  //break point here to get the results
}

#2


(EDIT: See bottom of post for benchmarks on different micro-optimizations of the method)

(编辑:有关该方法的不同微优化的基准,请参见帖子的底部)

Don't trim it - that might create a new string which you don't actually need. Instead, look through the string for any characters that aren't whitespace (for whatever definition you want). For example:

不要修剪它 - 这可能会创建一个你实际上并不需要的新字符串。相反,请查看字符串中是否有任何不是空格的字符(无论您想要什么样的定义)。例如:

public static bool IsEmptyOrWhitespace(string text)
{
    // Avoid creating iterator for trivial case
    if (text.Length == 0)
    {
        return true;
    }
    foreach (char c in text)
    {
        // Could use Char.IsWhiteSpace(c) instead
        if (c==' ' || c=='\t' || c=='\r' || c=='\n')
        {
            continue;
        }
        return false;
    }
    return true;
}

You might also consider what you want the method to do if text is null.

如果text为null,您可能还会考虑您希望该方法执行的操作。

Possible further micro-optimizations to experiment with:

可能进一步微观优化以进行试验:

  • Is foreach faster or slower than using a for loop like the one below? Note that with the for loop you can remove the "if (text.Length==0)" test at the start.

    foreach比使用下面的for循环更快还是更慢?请注意,使用for循环,您可以在开始时删除“if(text.Length == 0)”测试。

    for (int i = 0; i < text.Length; i++)
    {
        char c = text[i];
        // ...
    
  • Same as above, but hoisting the Length call. Note that this isn't good for normal arrays, but might be useful for strings. I haven't tested it.

    与上面相同,但是提升长度呼叫。请注意,这对于普通数组来说并不好,但可能对字符串很有用。我没有测试过。

    int length = text.Length;
    for (int i = 0; i < length; i++)
    {
        char c = text[i];
    
  • In the body of the loop, is there any difference (in speed) between what we've got and:

    在循环体中,我们得到的和之间有什么不同(速度):

    if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
    {
        return false;
    }
    
  • Would a switch/case be faster?

    开关/箱子会更快吗?

    switch (c)
    {
        case ' ': case '\r': case '\n': case '\t':
            return false;               
    }
    

Update on Trim behaviour

更新修剪行为

I've just been looking into how Trim can be as efficient as this. It seems that Trim will only create a new string if it needs to. If it can return this or "" it will:

我一直在研究Trim如何像这样高效。似乎Trim只会在需要时创建一个新字符串。如果它可以返回这个或“”它将:

using System;

class Test
{
    static void Main()
    {
        CheckTrim(string.Copy(""));
        CheckTrim("  ");
        CheckTrim(" x ");
        CheckTrim("xx");
    }

    static void CheckTrim(string text)
    {
        string trimmed = text.Trim();
        Console.WriteLine ("Text: '{0}'", text);
        Console.WriteLine ("Trimmed ref == text? {0}",
                          object.ReferenceEquals(text, trimmed));
        Console.WriteLine ("Trimmed ref == \"\"? {0}",
                          object.ReferenceEquals("", trimmed));
        Console.WriteLine();
    }
}

This means it's really important that any benchmarks in this question should use a mixture of data:

这意味着这个问题中的任何基准都应该使用混合数据,这一点非常重要:

  • Empty string
  • Whitespace
  • Whitespace surrounding text
  • 围绕文字的空白

  • Text without whitespace
  • 没有空格的文本

Of course, the "real world" balance between these four is impossible to predict...

当然,这四者之间的“现实世界”平衡是无法预测的......

Benchmarks I've run some benchmarks of the original suggestions vs mine, and mine appears to win in everything I throw at it, which surprises me given the results in other answers. However, I've also benchmarked the difference between foreach, for using text.Length, for using text.Length once and then reversing the iteration order, and for with a hoisted length.

基准我已经对我的原始建议进行了一些基准测试,并且我的投入似乎在我投入的所有内容中获胜,这让我感到惊讶,因为其他答案的结果。但是,我还使用text.Length,使用text.Length,然后反转迭代顺序,以及使用提升的长度,对foreach之间的差异进行基准测试。

Basically the for loop is very slightly faster, but hoisting the length check makes it slower than foreach. Reversing the for loop direction is very slightly slower than foreach too. I strongly suspect that the JIT is doing interesting things here, in terms of removing duplicate bounds checks etc.

基本上for循环非常快,但提升长度检查使它比foreach慢。反转for循环方向也比foreach慢一点。我强烈怀疑JIT在这里做了一些有趣的事情,包括删除重复的边界检查等。

Code: (see my benchmarking blog entry for the framework this is written against)

代码:(请参阅我的基准博客条目,该框架针对此编写)

using System;
using BenchmarkHelper;

public class TrimStrings
{
    static void Main()
    {
        Test("");
        Test(" ");
        Test(" x ");
        Test("x");
        Test(new string('x', 1000));
        Test(" " + new string('x', 1000) + " ");
        Test(new string(' ', 1000));
    }

    static void Test(string text)
    {
        bool expectedResult = text.Trim().Length == 0;
        string title = string.Format("Length={0}, result={1}", text.Length, 
                                     expectedResult);

        var results = TestSuite.Create(title, text, expectedResult)
/*            .Add(x => x.Trim().Length == 0, "Trim().Length == 0")
            .Add(x => x.Trim() == "", "Trim() == \"\"")
            .Add(x => x.Trim().Equals(""), "Trim().Equals(\"\")")
            .Add(x => x.Trim() == string.Empty, "Trim() == string.Empty")
            .Add(x => x.Trim().Equals(string.Empty), "Trim().Equals(string.Empty)")
*/
            .Add(OriginalIsEmptyOrWhitespace)
            .Add(IsEmptyOrWhitespaceForLoop)
            .Add(IsEmptyOrWhitespaceForLoopReversed)
            .Add(IsEmptyOrWhitespaceForLoopHoistedLength)
            .RunTests()                          
            .ScaleByBest(ScalingMode.VaryDuration);

        results.Display(ResultColumns.NameAndDuration | ResultColumns.Score,
                        results.FindBest());
    }

    public static bool OriginalIsEmptyOrWhitespace(string text)
    {
        if (text.Length == 0)
        {
            return true;
        }
        foreach (char c in text)
        {
            if (c==' ' || c=='\t' || c=='\r' || c=='\n')
            {
                continue;
            }
            return false;
        }
        return true;
    }

    public static bool IsEmptyOrWhitespaceForLoop(string text)
    {
        for (int i=0; i < text.Length; i++)
        {
            char c = text[i];
            if (c==' ' || c=='\t' || c=='\r' || c=='\n')
            {
                continue;
            }
            return false;
        }
        return true;
    }

    public static bool IsEmptyOrWhitespaceForLoopReversed(string text)
    {
        for (int i=text.Length-1; i >= 0; i--)
        {
            char c = text[i];
            if (c==' ' || c=='\t' || c=='\r' || c=='\n')
            {
                continue;
            }
            return false;
        }
        return true;
    }

    public static bool IsEmptyOrWhitespaceForLoopHoistedLength(string text)
    {
        int length = text.Length;
        for (int i=0; i < length; i++)
        {
            char c = text[i];
            if (c==' ' || c=='\t' || c=='\r' || c=='\n')
            {
                continue;
            }
            return false;
        }
        return true;
    }
}

Results:

============ Length=0, result=True ============
OriginalIsEmptyOrWhitespace             30.012 1.00
IsEmptyOrWhitespaceForLoop              30.802 1.03
IsEmptyOrWhitespaceForLoopReversed      32.944 1.10
IsEmptyOrWhitespaceForLoopHoistedLength 35.113 1.17

============ Length=1, result=True ============
OriginalIsEmptyOrWhitespace             31.150 1.04
IsEmptyOrWhitespaceForLoop              30.051 1.00
IsEmptyOrWhitespaceForLoopReversed      31.602 1.05
IsEmptyOrWhitespaceForLoopHoistedLength 33.383 1.11

============ Length=3, result=False ============
OriginalIsEmptyOrWhitespace             30.221 1.00
IsEmptyOrWhitespaceForLoop              30.131 1.00
IsEmptyOrWhitespaceForLoopReversed      34.502 1.15
IsEmptyOrWhitespaceForLoopHoistedLength 35.690 1.18

============ Length=1, result=False ============
OriginalIsEmptyOrWhitespace             31.626 1.05
IsEmptyOrWhitespaceForLoop              30.005 1.00
IsEmptyOrWhitespaceForLoopReversed      32.383 1.08
IsEmptyOrWhitespaceForLoopHoistedLength 33.666 1.12

============ Length=1000, result=False ============
OriginalIsEmptyOrWhitespace             30.177 1.00
IsEmptyOrWhitespaceForLoop              33.207 1.10
IsEmptyOrWhitespaceForLoopReversed      30.867 1.02
IsEmptyOrWhitespaceForLoopHoistedLength 31.837 1.06

============ Length=1002, result=False ============
OriginalIsEmptyOrWhitespace             30.217 1.01
IsEmptyOrWhitespaceForLoop              30.026 1.00
IsEmptyOrWhitespaceForLoopReversed      34.162 1.14
IsEmptyOrWhitespaceForLoopHoistedLength 34.860 1.16

============ Length=1000, result=True ============
OriginalIsEmptyOrWhitespace             30.303 1.01
IsEmptyOrWhitespaceForLoop              30.018 1.00
IsEmptyOrWhitespaceForLoopReversed      35.475 1.18
IsEmptyOrWhitespaceForLoopHoistedLength 40.927 1.36

#3


I really don't know which is faster; although my gut feeling says number one. But here's another method:

我真的不知道哪个更快;虽然我的直觉是第一名。但这是另一种方法:

if (String.IsNullOrEmpty(myString.Trim()))

#4


myString.Trim().Length == 0 Took : 421 ms

myString.Trim()。Length == 0 Took:421 ms

myString.Trim() == '' took : 468 ms

myString.Trim()==''花了:468毫秒

if (myString.Trim().Equals("")) Took : 515 ms

if(myString.Trim()。Equals(“”)):515 ms

if (myString.Trim() == String.Empty) Took : 484 ms

if(myString.Trim()== String.Empty)Took:484 ms

if (myString.Trim().Equals(String.Empty)) Took : 500 ms

if(myString.Trim()。Equals(String.Empty))Took:500 ms

if (string.IsNullOrEmpty(myString.Trim())) Took : 437 ms

if(string.IsNullOrEmpty(myString.Trim()))Took:437 ms

In my tests, it looks like myString.Trim().Length == 0 and surprisingly, string.IsNullOrEmpty(myString.Trim()) were consistently the fastest. The results above are a typical result from doing 10,000,000 comparisons.

在我的测试中,它看起来像myString.Trim()。Length == 0并且令人惊讶的是,string.IsNullOrEmpty(myString.Trim())始终是最快的。上述结果是进行10,000,000次比较的典型结果。

#5


Checking the length of a string for being zero is the most efficient way to test for an empty string, so I would say number 1:

检查字符串的长度为零是测试空字符串的最有效方法,所以我想说数字1:

if (myString.Trim().Length == 0)

The only way to optimize this further might be to avoid trimming by using a compiled regular expression (Edit: this is actually much slower than using Trim().Length).

进一步优化这种方法的唯一方法可能是避免使用编译的正则表达式进行修剪(编辑:这实际上比使用Trim()慢得多。长度)。

Edit: The suggestion to use Length came from a FxCop guideline. I've also just tested it: it's 2-3 times faster than comparing to an empty string. However both approaches are still extremely fast (we're talking nanoseconds) - so it hardly matters which one you use. Trimming is so much more of a bottleneck it's hundreds of times slower than the actual comparison at the end.

编辑:使用Length的建议来自FxCop指南。我也刚刚对它进行了测试:它比空字符串快2-3倍。然而,这两种方法仍然非常快(我们说的是纳秒) - 所以你使用哪种方法几乎不重要。修剪是一个瓶颈,它比最后的实际比较慢几百倍。

#6


String.IsNullOrWhitespace in .NET 4 Beta 2 also plays in this space and doesnt need to be custom written

.NET 4 Beta 2中的String.IsNullOrWhitespace也在这个空间中播放,不需要自定义编写

#7


Since I just started I can't comment so here it is.

自从我刚开始以来,我不能发表评论,所以在这里。

if (String.IsNullOrEmpty(myString.Trim()))

Trim() call will fail if myString is null since you can't call methods in a object that is null (NullReferenceException).

如果myString为null,则Trim()调用将失败,因为您无法调用null(NullReferenceException)对象中的方法。

So the correct syntax would be something like this:

所以正确的语法是这样的:

if (!String.IsNullOrEmpty(myString))
{
    string trimmedString = myString.Trim();
    //do the rest of you code
}
else
{
    //string is null or empty, don't bother processing it
}

#8


public static bool IsNullOrEmpty(this String str, bool checkTrimmed)
{
  var b = String.IsNullOrEmpty(str);
  return checkTrimmed ? b && str.Trim().Length == 0 : b;
}