检查字符串内容? string Length Vs Empty String

时间:2008-08-13 19:03:28

标签: string optimization language-agnostic compiler-construction

哪种编译器更有效,以及检查字符串是否为空的最佳实践?

  1. 检查字符串的长度是否== 0
  2. 检查字符串是否为空(strVar ==“”)
  3. 此外,答案是否取决于语言?

13 个答案:

答案 0 :(得分:15)

是的,这取决于语言,因为不同语言之间的字符串存储不同。

  • Pascal类型字符串:Length = 0
  • C风格的字符串:[0] == 0
  • .NET:.IsNullOrEmpty

等。

答案 1 :(得分:14)

在使用C风格(以null结尾)字符串的语言中,与""进行比较会更快。这是一个O(1)操作,而采用C风格字符串的长度是O(n)。

在将长度存储为字符串对象(C#,Java,...)的一部分的语言中,检查长度也是O(1)。在这种情况下,直接检查长度更快,因为它避免了构造新空字符串的开销。

答案 2 :(得分:2)

在.Net:

string.IsNullOrEmpty( nystr );

字符串可以为null,因此.Length有时会抛出NullReferenceException

答案 3 :(得分:2)

  

在使用C风格(以null结尾)字符串的语言中,与“”相比会更快

实际上,检查字符串中的第一个字符是否为'\ 0'可能更好:

char *mystring;
/* do something with the string */
if ((mystring != NULL) && (mystring[0] == '\0')) {
    /* the string is empty */
}

在Perl中有第三个选项,字符串是未定义的。这与C中的NULL指针略有不同,只是因为您没有因访问未定义的字符串而出现分段错误。

答案 4 :(得分:1)

在Java 1.6中,String类有一个新方法isEmpty

还有Jakarta commons库,它有isBlank方法。空白被定义为仅包含空格的字符串。

答案 5 :(得分:1)

String.IsNullOrEmpty()仅适用于.net 2.0及以上版本,对于.net 1 / 1.1,我倾向于使用:

if (inputString == null || inputString == String.Empty)
{
    // String is null or empty, do something clever here. Or just expload.
}

我使用String.Empty而不是“”因为“”会创建一个对象,而String.Empty不会 - 我知道它的东西小而琐碎,但是当我不需要它时,id仍然不是创建对象! (Source

答案 6 :(得分:1)

假设你的问题是.NET:

如果你想验证你的字符串是否反对nullity也使用IsNullOrEmpty,如果你已经知道你的字符串不是null,例如在检查TextBox.Text等时,不要使用IsNullOrEmpty,然后进入你的问题。
所以对我来说,String.Length的性能低于字符串比较。

我对事件进行了测试(我也用C#进行了测试,结果相同):

Module Module1
  Sub Main()
    Dim myString = ""


    Dim a, b, c, d As Long

    Console.WriteLine("Way 1...")

    a = Now.Ticks
    For index = 0 To 10000000
      Dim isEmpty = myString = ""
    Next
    b = Now.Ticks

    Console.WriteLine("Way 2...")

    c = Now.Ticks
    For index = 0 To 10000000
      Dim isEmpty = myString.Length = 0
    Next
    d = Now.Ticks

    Dim way1 = b - a, way2 = d - c

    Console.WriteLine("way 1 took {0} ticks", way1)
    Console.WriteLine("way 2 took {0} ticks", way2)
    Console.WriteLine("way 1 took {0} ticks more than way 2", way1 - way2)
    Console.Read()
  End Sub
End Module

结果:

Way 1...
Way 2...
way 1 took 624001 ticks
way 2 took 468001 ticks
way 1 took 156000 ticks more than way 2

这意味着比较比字符串长度检查更多。

答案 7 :(得分:0)

实际上,IMO最好的确定方法是字符串类的IsNullOrEmpty()方法。

http://msdn.microsoft.com/en-us/library/system.string.isnullorempty.

更新:我认为.Net,在其他语言中,这可能会有所不同。

答案 8 :(得分:0)

  

在这种情况下,直接检查长度更快,因为它避免了构造新空字符串的开销。

@DerekPark:这并非总是如此。 “”是一个字符串文字,因此,在Java中,它几乎肯定已经被实习。

答案 9 :(得分:0)

对于C字符串,

if (s[0] == 0)

会比

更快
if (strlen(s) == 0)

if (strcmp(s, "") == 0)

因为你会避免函数调用的开销。

答案 10 :(得分:0)

@Nathan

  

实际上,检查字符串中的第一个字符是否为'\ 0'可能更好:

我几乎提到了这一点,但最终还是将其遗漏了,因为用空字符串调用strcmp()并直接检查字符串中的第一个字符都是O(1)。你基本上只需支付一个额外的函数调用,这是非常便宜的。但是,如果确实需要绝对最佳速度,那么肯定会采用直接的第一个char-to-0比较。

老实说,我总是使用strlen() == 0,因为我从不编写了一个程序,这实际上是一个可测量的性能问题,我认为这是表达检查最可读的方式。

答案 11 :(得分:0)

同样,在不知道语言的情况下,这是不可能的。

但是,我建议您选择对随后的维护程序员最有意义的技术,并且必须保持您的工作。

我建议编写一个明确做你想要的功能,比如

#define IS_EMPTY(s) ((s)[0]==0)

或类似的。现在毫无疑问,你正在检查。

答案 12 :(得分:0)

在我读完这篇帖子后,我进行了一个小实验,产生了两个截然不同且有趣的发现。

请考虑以下事项。

strInstallString    "1" string

以上是从Visual Studio调试器的locals窗口复制的。在以下所有三个示例中都使用相同的值。

if(strInstallString =="")=== if(strInstallString == string.Empty)

以下是Visual Studio 2013调试器的反汇编窗口中显示的代码,用于这两个基本相同的情况。

if ( strInstallString == "" )
003126FB  mov         edx,dword ptr ds:[31B2184h]
00312701  mov         ecx,dword ptr [ebp-50h]
00312704  call        59DEC0B0            ; On return, EAX = 0x00000000.
00312709  mov         dword ptr [ebp-9Ch],eax
0031270F  cmp         dword ptr [ebp-9Ch],0
00312716  sete        al
00312719  movzx       eax,al
0031271C  mov         dword ptr [ebp-64h],eax
0031271F  cmp         dword ptr [ebp-64h],0
00312723  jne         00312750

if ( strInstallString == string.Empty )
00452443  mov         edx,dword ptr ds:[3282184h]
00452449  mov         ecx,dword ptr [ebp-50h]
0045244C  call        59DEC0B0        ; On return, EAX = 0x00000000.
00452451  mov         dword ptr [ebp-9Ch],eax
00452457  cmp         dword ptr [ebp-9Ch],0
0045245E  sete        al
00452461  movzx       eax,al
00452464  mov         dword ptr [ebp-64h],eax
00452467  cmp         dword ptr [ebp-64h],0
0045246B  jne         00452498

if(strInstallString == string.Empty)显着不同

if ( strInstallString.Length == 0 )
003E284B  mov         ecx,dword ptr [ebp-50h]
003E284E  cmp         dword ptr [ecx],ecx
003E2850  call        5ACBC87E        ; On return, EAX = 0x00000001.
003E2855  mov         dword ptr [ebp-9Ch],eax
003E285B  cmp         dword ptr [ebp-9Ch],0
003E2862  setne       al
003E2865  movzx       eax,al
003E2868  mov         dword ptr [ebp-64h],eax
003E286B  cmp         dword ptr [ebp-64h],0
003E286F  jne         003E289C

从上面的机器代码清单,由.NET Framework的NGEN模块4.5版生成,我得出以下结论。

  1. 对于所有实际目的,测试与空字符串文字和System.string类上的静态string.Empty属性的相等性是相同的。两个代码片段之间的唯一区别是第一个移动指令的来源,两者都是相对于ds的偏移量,这意味着两者都引用了烘焙常量。

  2. 测试空字符串的相等性,无论是文字还是string.Empty属性,都会设置一个双参数函数调用,通过返回零来指示不等式。我将这个结论建立在我几个月前进行的其他测试的基础上,其中我在管理/非管理的鸿沟中追踪了我自己的一些代码。在所有情况下,任何需要两个或多个参数的调用都会将第一个参数放在寄存器ECX中,而第二个参数放在寄存器EDX中。我不记得后来的论点是如何通过的。然而,呼叫设置看起来更像__fastcall而不是__stdcall。同样,预期的返回值总是出现在寄存器EAX中,这几乎是通用的。

  3. 测试字符串的长度会设置一个参数的函数调用,它返回1(在寄存器EAX中),这恰好是被测试字符串的长度。

  4. 鉴于立即可见的机器代码几乎完全相同,我能想象的唯一原因是, Shinny 报告的刺激长度的字符串相等性能更好执行比较的双参数函数比从字符串实例读取长度的单参数函数更好地优化。

  5. <强>结论

    作为一个原则问题,我避免将空字符串作为文字进行比较,因为空字符串文字在源代码中可能显得不明确。为此,我的.NET帮助器类已经将空字符串定义为常量。虽然我使用 string.Empty 进行直接内联比较,但常量会保留其用于定义其值为空字符串的其他常量,因为不能为常量赋值 string.Empty 作为它的价值。

    本练习一劳永逸地解决了我对可能与 string.Empty 或我的助手类定义的常量进行比较的成本(如果有的话)的关注。

    然而,它也提出了一个令人费解的问题来取代它;为什么与 string.Empty 进行比较比测试字符串的长度更有效?或者Shinny使用的测试是否因为循环的实现方式而失效? (我觉得很难相信,但是,我再次被愚弄了,因为我确定你也有!)

    我一直认为 system.string 对象是计数字符串,从根本上类似于我们早知道的长期建立的基本字符串(BSTR)。