【问题标题】:Checking for string contents? string Length Vs Empty String检查字符串内容?字符串长度与空字符串
【发布时间】:2010-09-05 19:56:21
【问题描述】:

对于编译器和检查字符串是否为空的最佳实践,哪个更有效?

  1. 检查字符串长度是否== 0
  2. 检查字符串是否为空(strVar == "")

另外,答案是否取决于语言?

【问题讨论】:

    标签: string optimization language-agnostic compiler-construction


    【解决方案1】:

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

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

    等等。

    【讨论】:

    • 我认为 OP 询问的是空白字符串验证,而不是空字符串,所以当您已经知道字符串不为空时,使用 IsNullOrEmpty 只是另一个不必要的检查。所以 OP 的问题是什么需要更高的性能,myString.Length > 0 或 myString != ""。阅读stackoverflow.com/questions/10230/…
    【解决方案2】:

    在使用 C 样式(空终止)字符串的语言中,与 "" 相比会更快。这是一个 O(1) 操作,而 C 风格字符串的长度是 O(n)。

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

    【讨论】:

    • 在 C# 中,如果您与 string.Empty 进行比较,那么您就是在与已经构建的字符串进行比较。然后也是 O(1)。
    【解决方案3】:

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

    其实最好检查一下字符串的第一个char是否为'\0':

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

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

    【讨论】:

      【解决方案4】:

      在 .Net 中:

      string.IsNullOrEmpty( nystr );
      

      字符串可以为空,所以 .Length 有时会抛出 NullReferenceException

      【讨论】:

        【解决方案5】:

        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 不会 - 我知道它是一些小而琐碎的东西,但是当我不需要它们时,我仍然宁愿不创建对象! (Source)

        【讨论】:

        • 如果 "" 真的导致 C# 编译器内部的实例化,我会感到非常惊讶。
        • 使用 'inputString.Length == 0',而不是 'inputString == String.Empty' 以获得更好的性能
        【解决方案6】:

        对于 C 字符串,

        if (s[0] == 0)
        

        会比任何一个都快

        if (strlen(s) == 0)
        

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

        因为您将避免函数调用的开销。

        【讨论】:

          【解决方案7】:

          假设您的问题是 .NET:

          如果你想验证你的字符串是否为 null 以及使用 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
          

          这意味着比较不仅仅是字符串长度检查。

          【讨论】:

          • 但是,在 .Net 中,您可以通过与 string.Empty 而不是空字符串 ("") 进行比较来避免显式字符串比较。这应该使它成为一个 O(1) 操作。
          • 我认为 string.Empty 和 "" 是一样的文字,我真的不明白。
          • string.Empty 是字符串类的实例,其值为 ""。但是,Equals 和 (==) 的字符串重载将在对字符进行字符比较之前进行参考比较。如果引用相等,则跳过字符比较。因此,将 string.Empty 值与 string.Empty 进行比较将明显快于将其与 "" 进行比较,后者将生成一个新的字符串对象并将其初始值设置为 ""。它们不一样。
          【解决方案8】:

          读完这个帖子后,我做了一个小实验,得出了两个截然不同且有趣的发现。

          考虑以下内容。

          strInstallString    "1" string
          

          以上内容是从 Visual Studio 调试器的本地窗口复制而来的。以下三个示例都使用相同的值。

          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 4.5 的NGEN 模块生成的机器代码清单,我得出以下结论。

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

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

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

          4. 鉴于立即可见的机器代码几乎相同,我能想象到的唯一原因是字符串相等性在 Shinny 报告的字符串长度上具有更好的性能是执行比较的双参数函数明显优于从字符串实例中读取长度的单参数函数。

          结论

          原则上,我避免将空字符串作为文字进行比较,因为空字符串文字在源代码中可能会显得模棱两可。为此,我的 .NET 帮助程序类早就将空字符串定义为常量。尽管我使用 string.Empty 进行直接的内联比较,但该常量仍可用于定义其他值为空字符串的常量,因为不能为常量分配 string.Empty 作为它的值。

          这个练习一劳永逸地解决了我对与 string.Empty 或我的助手类定义的常量进行比较的成本(如果有的话)的任何担忧。

          但是,它也提出了一个令人费解的问题来替换它;为什么与 string.Empty 比较比测试字符串的长度更有效?或者由于循环的实现方式,Shinny 使用的测试是否无效? (我觉得这很难相信,但话说回来,我以前也被愚弄过,我相信你也一样!)

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

          【讨论】:

            【解决方案9】:

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

            还有 Jakarta commons library,它有 [isBlank] 2 方法。空白定义为只包含空格的字符串。

            【讨论】:

              【解决方案10】:

              其实IMO最好的判断方法是字符串类的IsNullOrEmpty()方法。

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

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

              【讨论】:

                【解决方案11】:

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

                @DerekPark:这并不总是正确的。 "" 是一个字符串字面量,所以在 Java 中,几乎可以肯定它已经被实习了。

                【讨论】:

                  【解决方案12】:

                  @内森

                  其实最好检查一下字符串的第一个char是否为'\0':

                  我几乎提到了这一点,但最后没有提到,因为使用空字符串调用strcmp() 并直接检查字符串中的第一个字符都是 O(1)。您基本上只需为额外的函数调用付费,这非常便宜。但是,如果您真的需要绝对的最佳速度,那么一定要进行直接的 first-char-to-0 比较。

                  老实说,我一直使用strlen() == 0,因为我从来没有写过一个程序,这实际上是一个可测量的性能问题,我认为这是表达检查的最易读的方式。 p>

                  【讨论】:

                    【解决方案13】:

                    同样,不懂语言,是无法分辨的。

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

                    我建议编写一个明确执行您想要的功能的函数,例如

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

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

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2017-08-19
                      • 2015-06-23
                      • 2016-02-26
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-03-03
                      • 2018-11-28
                      • 1970-01-01
                      相关资源
                      最近更新 更多