Frage

Was ist für den Compiler effizienter und die beste Vorgehensweise zum Überprüfen, ob eine Zeichenfolge leer ist?

  1. Prüfen, ob die Länge der Zeichenfolge == 0 ist
  2. Prüfen, ob der String leer ist (strVar == "")

Hängt die Antwort auch von der Sprache ab?

War es hilfreich?

Lösung

Ja, es hängt von der Sprache ab, da die Zeichenfolgenspeicherung je nach Sprache unterschiedlich ist.

  • Zeichenfolgen vom Typ Pascal: Length = 0.
  • Saiten im C-Stil: [0] == 0.
  • .NETZ: .IsNullOrEmpty.

Usw.

Andere Tipps

In Sprachen, die Zeichenfolgen im C-Stil (nullterminiert) verwenden, im Vergleich zu "" wird schneller sein.Das ist eine O(1)-Operation, während die Länge einer Zeichenfolge im C-Stil O(n) ist.

In Sprachen, die die Länge als Teil des String-Objekts speichern (C#, Java, ...), ist die Überprüfung der Länge ebenfalls O(1).In diesem Fall ist die direkte Überprüfung der Länge schneller, da dadurch der Aufwand für die Erstellung der neuen leeren Zeichenfolge vermieden wird.

In .Net:

string.IsNullOrEmpty( nystr );

Zeichenfolgen können null sein, daher löst .Length manchmal eine NullReferenceException aus

In Sprachen, die Zeichenfolgen im C-Stil (nullterminiert) verwenden, ist der Vergleich mit „“ schneller

Tatsächlich ist es möglicherweise besser zu überprüfen, ob das erste Zeichen in der Zeichenfolge „\0“ ist:

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

In Perl gibt es eine dritte Option, nämlich dass der String undefiniert ist.Dies unterscheidet sich ein wenig von einem NULL-Zeiger in C, schon allein deshalb, weil beim Zugriff auf eine undefinierte Zeichenfolge kein Segmentierungsfehler auftritt.

In Java 1.6 verfügt die String-Klasse über eine neue Methode ist leer

Es gibt auch die Jakarta Commons Library, die über die verfügt ist leer Methode.Leerzeichen ist als Zeichenfolge definiert, die nur Leerzeichen enthält.

Angenommen, Ihre Frage ist .NET:

Wenn Sie Ihre Zeichenfolge auch gegen Null validieren möchten, verwenden Sie IsNullOrEmpty. Wenn Sie bereits wissen, dass Ihre Zeichenfolge nicht null ist, z. B. beim Überprüfen von TextBox.Text usw., verwenden Sie IsNullOrEmpty nicht, und dann kommt Ihre Frage.
Meiner Meinung nach ist String.Length also weniger leistungsfähig als der String-Vergleich.

Ich habe es zufällig getestet (ich habe es auch mit C# getestet, dasselbe Ergebnis):

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

Ergebnis:

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

Das bedeutet, dass der Vergleich weitaus mehr erfordert als die Überprüfung der Zeichenfolgenlänge.

String.IsNullOrEmpty() Funktioniert nur auf .net 2.0 und höher, für .net 1/1.1 verwende ich normalerweise:

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

Ich verwende String.Empty im Gegensatz zu „“, weil „“ ein Objekt erstellt, während String.Empty dies nicht tut – ich weiß, dass es etwas Kleines und Triviales ist, aber ich würde trotzdem lieber keine Objekte erstellen, wenn ich sie nicht brauche!(Quelle)

Tatsächlich ist meiner Meinung nach die beste Methode zur Bestimmung die IsNullOrEmpty()-Methode der String-Klasse.

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

Aktualisieren:Ich ging von .Net aus, in anderen Sprachen könnte das anders sein.

In diesem Fall ist die direkte Überprüfung der Länge schneller, da dadurch der Aufwand für die Erstellung der neuen leeren Zeichenfolge vermieden wird.

@DerekPark:Das ist nicht immer richtig.„“ ist ein String-Literal und wird daher in Java mit ziemlicher Sicherheit bereits interniert sein.

Für C-Saiten:

if (s[0] == 0)

wird schneller sein als beides

if (strlen(s) == 0)

oder

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

weil Sie den Overhead eines Funktionsaufrufs vermeiden.

@Nathan

Tatsächlich ist es möglicherweise besser zu prüfen, ob das erste Zeichen in der Zeichenfolge „\0“ ist:

Das hätte ich fast erwähnt, aber am Ende habe ich es weggelassen, seit ich angerufen habe strcmp() mit der leeren Zeichenfolge und die direkte Überprüfung des ersten Zeichens in der Zeichenfolge sind beide O(1).Sie zahlen im Grunde nur für einen zusätzlichen Funktionsaufruf, was ziemlich günstig ist.Wenn du Wirklich Wenn Sie jedoch die absolut beste Geschwindigkeit benötigen, sollten Sie auf jeden Fall einen direkten First-Char-to-0-Vergleich durchführen.

Ehrlich gesagt benutze ich immer strlen() == 0, weil ich habe niemals Ich habe ein Programm geschrieben, bei dem es sich tatsächlich um ein messbares Leistungsproblem handelte, und ich denke, das ist die am besten lesbare Art, die Überprüfung auszudrücken.

Auch hier ist es ohne Kenntnis der Sprache unmöglich zu sagen.

Ich empfehle jedoch, dass Sie die Technik wählen, die für den folgenden Wartungsprogrammierer am sinnvollsten ist und Ihre Arbeit warten muss.

Ich würde empfehlen, eine Funktion zu schreiben, die explizit das tut, was Sie wollen, z

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

oder vergleichbar.Es besteht kein Zweifel daran, dass Sie es überprüfen.

Nachdem ich diesen Thread gelesen hatte, führte ich ein kleines Experiment durch, das zwei unterschiedliche und interessante Ergebnisse lieferte.

Folgendes berücksichtigen.

strInstallString    "1" string

Das Obige wurde aus dem lokalen Fenster des Visual Studio-Debuggers kopiert.In allen drei folgenden Beispielen wird derselbe Wert verwendet.

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

Im Folgenden wird der Code im Disassemblierungsfenster des Visual Studio 2013-Debuggers für diese beiden grundsätzlich identischen Fälle angezeigt.

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 ) ist nicht wesentlich unterschiedlich

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

Aus den obigen Maschinencode-Auflistungen, die vom NGEN-Modul des .NET Framework, Version 4.5, generiert wurden, ziehe ich die folgenden Schlussfolgerungen.

  1. Das Testen auf Gleichheit mit dem leeren Zeichenfolgenliteral und der statischen string.Empty-Eigenschaft der System.string-Klasse ist für alle praktischen Zwecke identisch.Der einzige Unterschied zwischen den beiden Codeschnipseln besteht in der Quelle der ersten Bewegungsanweisung, und beide sind Offsets relativ zu ds, was bedeutet, dass sich beide auf eingebaute Konstanten beziehen.

  2. Beim Testen auf Gleichheit mit der leeren Zeichenfolge, entweder als Literal oder als string.Empty-Eigenschaft, wird ein Funktionsaufruf mit zwei Argumenten eingerichtet, der angibt Ungleichheit durch die Rückgabe von Null.Ich stütze diese Schlussfolgerung auf andere Tests, die ich vor ein paar Monaten durchgeführt habe und bei denen ich einen Teil meines eigenen Codes über die verwaltete/nicht verwaltete Grenze hinweg und zurück verfolgt habe.In allen Fällen legt jeder Aufruf, der zwei oder mehr Argumente erfordert, das erste Argument im Register ECX und das zweite im Register EDX ab.Ich kann mich nicht erinnern, wie spätere Argumente weitergegeben wurden.Dennoch ähnelte der Anrufaufbau eher __fastcall als __stdcall.Ebenso wurden die erwarteten Rückgabewerte immer im Register EAX angezeigt, was nahezu universell ist.

  3. Durch das Testen der Länge der Zeichenfolge wird ein Funktionsaufruf mit einem Argument eingerichtet, der 1 (im Register EAX) zurückgibt, was zufällig der Länge der getesteten Zeichenfolge entspricht.

  4. Angesichts der Tatsache, dass der sofort sichtbare Maschinencode nahezu identisch ist, ist dies der einzige Grund, den ich mir vorstellen kann, der für die bessere Leistung der String-Gleichheit über die von gemeldete String-Länge verantwortlich ist Shinny ist, dass die Funktion mit zwei Argumenten, die den Vergleich durchführt, wesentlich besser optimiert ist als die Funktion mit einem Argument, die die Länge aus der Zeichenfolgeninstanz liest.

Abschluss

Grundsätzlich vermeide ich den Vergleich mit dem leeren String als Literal, da das leere String-Literal im Quellcode mehrdeutig erscheinen kann.Zu diesem Zweck definieren meine .NET-Hilfsklassen seit langem die leere Zeichenfolge als Konstante.Obwohl ich es benutze string.Empty Bei direkten Inline-Vergleichen verdient die Konstante ihren Unterhalt für die Definition anderer Konstanten, deren Wert die leere Zeichenfolge ist, da eine Konstante nicht zugewiesen werden kann string.Empty als dessen Wert.

Diese Übung zerstreut ein für alle Mal alle Bedenken, die ich hinsichtlich der Kosten, wenn überhaupt, eines Vergleichs mit beiden habe string.Empty oder die von meinen Hilfsklassen definierte Konstante.

Allerdings wirft es auch eine rätselhafte Frage auf, ob es ersetzt werden soll.Warum vergleicht man mit string.Empty effizienter als das Testen der Länge der Zeichenfolge?Oder ist der von Shinny verwendete Test aufgrund der Art und Weise, wie die Schleife implementiert ist, ungültig?(Ich kann das kaum glauben, aber andererseits wurde ich auch schon einmal getäuscht, und ich bin mir sicher, dass Sie das auch getan haben!)

Das habe ich schon lange vermutet system.string Objekte waren gezählte Strings, im Wesentlichen ähnlich dem seit langem etablierten Basic String (BSTR), den wir seit langem von COM kennen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top