Question

Qu'est-ce qui est le plus efficace pour le compilateur et quelle est la meilleure pratique pour vérifier si une chaîne est vide ?

  1. Vérifier si la longueur de la chaîne == 0
  2. Vérifier si la chaîne est vide (strVar == "")

Aussi, la réponse dépend-elle de la langue ?

Était-ce utile?

La solution

Oui, cela dépend de la langue, puisque le stockage des chaînes diffère selon les langues.

  • Chaînes de type Pascal : Length = 0.
  • Chaînes de style C : [0] == 0.
  • .FILET: .IsNullOrEmpty.

Etc.

Autres conseils

Dans les langages qui utilisent des chaînes de style C (terminées par un caractère nul), par rapport à "" sera plus rapide.C'est une opération O(1), alors que la longueur d'une chaîne de style C est O(n).

Dans les langages qui stockent la longueur dans le cadre de l'objet chaîne (C#, Java, ...), la vérification de la longueur est également O(1).Dans ce cas, vérifier directement la longueur est plus rapide, car cela évite la surcharge liée à la construction de la nouvelle chaîne vide.

Dans .Net :

string.IsNullOrEmpty( nystr );

les chaînes peuvent être nulles, donc .Length lève parfois une NullReferenceException

Dans les langages qui utilisent des chaînes de style C (terminées par un caractère nul), la comparaison avec "" sera plus rapide

En fait, il serait peut-être préférable de vérifier si le premier caractère de la chaîne est « \0 » :

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

En Perl, il existe une troisième option, à savoir que la chaîne n'est pas définie.C'est un peu différent d'un pointeur NULL en C, ne serait-ce que parce que vous n'obtenez pas d'erreur de segmentation pour accéder à une chaîne non définie.

Dans Java 1.6, la classe String a une nouvelle méthode est vide

Il existe également la bibliothèque commune de Jakarta, qui possède le est vide méthode.Blank est défini comme une chaîne qui contient uniquement des espaces.

En supposant que votre question soit .NET :

Si vous souhaitez également valider votre chaîne contre la nullité, utilisez IsNullOrEmpty, si vous savez déjà que votre chaîne n'est pas nulle, par exemple lors de la vérification de TextBox.Text etc., n'utilisez pas IsNullOrEmpty, et cela entre ensuite dans votre question.
Donc, à mon avis, String.Length est moins performant que la comparaison de chaînes.

Je l'ai testé (j'ai aussi testé avec C#, même résultat) :

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

Résultat:

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

Ce qui signifie que la comparaison nécessite bien plus que la vérification de la longueur des chaînes.

String.IsNullOrEmpty() ne fonctionne que sur .net 2.0 et supérieur, pour .net 1/1.1, j'ai tendance à utiliser :

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

J'utilise String.Empty par opposition à "" parce que "" créera un objet, alors que String.Empty ne le fera pas - je sais que c'est quelque chose de petit et de trivial, mais je préfère quand même ne pas créer d'objets quand je n'en ai pas besoin !(Source)

En fait, selon l'OMI, le meilleur moyen de déterminer est la méthode IsNullOrEmpty() de la classe de chaîne.

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

Mise à jour:J'ai supposé que .Net, dans d'autres langues, cela pourrait être différent.

Dans ce cas, vérifier directement la longueur est plus rapide, car cela évite la surcharge liée à la construction de la nouvelle chaîne vide.

@DerekPark :Ce n'est pas toujours vrai."" est une chaîne littérale donc, en Java, elle sera presque certainement déjà internée.

Pour les chaînes C,

if (s[0] == 0)

sera plus rapide que l'un ou l'autre

if (strlen(s) == 0)

ou

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

car vous éviterez la surcharge d’un appel de fonction.

@Nathan

En fait, il serait peut-être préférable de vérifier si le premier caractère de la chaîne est « \0 » :

J'ai failli le mentionner, mais j'ai fini par le laisser de côté, depuis que j'ai appelé strcmp() avec la chaîne vide et la vérification directe du premier caractère de la chaîne sont tous deux O(1).En gros, vous payez simplement pour un appel de fonction supplémentaire, ce qui est assez bon marché.Si tu vraiment Cependant, vous avez besoin de la meilleure vitesse absolue, optez certainement pour une comparaison directe du premier caractère à 0.

Honnêtement, j'utilise toujours strlen() == 0, parce que j'ai jamais j'ai écrit un programme où il s'agissait en fait d'un problème de performances mesurable, et je pense que c'est la manière la plus lisible d'exprimer le contrôle.

Encore une fois, sans connaître la langue, il est impossible de le savoir.

Je vous recommande cependant de choisir la technique qui fait le plus de sens pour le programmeur de maintenance qui suivra et qui devra entretenir votre travail.

Je recommanderais d'écrire une fonction qui fait explicitement ce que vous voulez, comme

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

ou comparable.Maintenant, il n'y a aucun doute sur le fait que vous vérifiez.

Après avoir lu ce fil de discussion, j’ai mené une petite expérience qui a donné deux résultats distincts et intéressants.

Considérer ce qui suit.

strInstallString    "1" string

Ce qui précède est copié à partir de la fenêtre locale du débogueur Visual Studio.La même valeur est utilisée dans les trois exemples suivants.

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

Voici le code affiché dans la fenêtre de désassemblage du débogueur Visual Studio 2013 pour ces deux cas fondamentalement identiques.

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 ) n'est pas significativement différent

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

À partir des listes de codes machine ci-dessus, générées par le module NGEN du .NET Framework, version 4.5, je tire les conclusions suivantes.

  1. Les tests d'égalité par rapport à la chaîne littérale vide et à la propriété string.Empty statique de la classe System.string sont, à toutes fins pratiques, identiques.La seule différence entre les deux extraits de code est la source de la première instruction de déplacement, et les deux sont des décalages par rapport à ds, ce qui implique que les deux font référence à des constantes intégrées.

  2. Le test d'égalité par rapport à la chaîne vide, en tant que littéral ou propriété string.Empty, configure un appel de fonction à deux arguments, qui indique inégalité en renvoyant zéro.Je base cette conclusion sur d'autres tests que j'ai effectués il y a quelques mois, dans lesquels j'ai suivi une partie de mon propre code à travers la division géré/non géré et inversement.Dans tous les cas, tout appel nécessitant deux arguments ou plus place le premier argument dans le registre ECX et le second dans le registre EDX.Je ne me souviens pas comment les arguments ultérieurs ont été adoptés.Néanmoins, la configuration de l'appel ressemblait plus à __fastcall qu'à __stdcall.De même, les valeurs de retour attendues apparaissaient toujours dans le registre EAX, qui est presque universel.

  3. Tester la longueur de la chaîne définit un appel de fonction à un argument, qui renvoie 1 (dans le registre EAX), qui se trouve être la longueur de la chaîne testée.

  4. Étant donné que le code machine immédiatement visible est presque identique, la seule raison que j'imagine qui expliquerait les meilleures performances de l'égalité des chaînes sur la longueur de la chaîne rapportée par Brillant est que la fonction à deux arguments qui effectue la comparaison est nettement mieux optimisée que la fonction à un argument qui lit la longueur de l'instance de chaîne.

Conclusion

Par principe, j'évite de comparer la chaîne vide en tant que littéral, car la chaîne vide littérale peut paraître ambiguë dans le code source.À cette fin, mes classes d'assistance .NET définissent depuis longtemps la chaîne vide comme une constante.Même si j'utilise chaîne.Vide pour les comparaisons directes en ligne, la constante gagne son argent pour définir d'autres constantes dont la valeur est la chaîne vide, car une constante ne peut pas être affectée chaîne.Vide comme sa valeur.

Cet exercice dissipe, une fois pour toutes, toute inquiétude que je pourrais avoir concernant le coût, le cas échéant, de la comparaison avec l'un ou l'autre chaîne.Vide ou la constante définie par mes classes d'assistance.

Cependant, cela soulève également une question déroutante : son remplacement ;pourquoi comparer avec chaîne.Vide plus efficace que de tester la longueur de la chaîne ?Ou le test utilisé par Shinny est-il invalidé à cause de la manière dont la boucle est implémentée ?(Je trouve cela difficile à croire, mais là encore, j'ai déjà été dupé, et je suis sûr que vous aussi !)

J'ai longtemps supposé que système.string les objets étaient des chaînes comptées, fondamentalement similaires à la chaîne de base (BSTR) établie de longue date que nous connaissons depuis longtemps grâce à COM.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top