Domanda

Qual è la soluzione più efficiente per il compilatore e la procedura migliore per verificare se una stringa è vuota?

  1. Verifica se la lunghezza della stringa == 0
  2. Verifica se la stringa è vuota (strVar == "")

Inoltre, la risposta dipende dalla lingua?

È stato utile?

Soluzione

Sì, dipende dalla lingua, poiché la memorizzazione delle stringhe differisce da una lingua all'altra.

  • Stringhe di tipo Pascal: Length = 0.
  • Stringhe in stile C: [0] == 0.
  • .NETTO: .IsNullOrEmpty.

Eccetera.

Altri suggerimenti

Nei linguaggi che utilizzano stringhe in stile C (con terminazione null), rispetto a "" sarà più veloce.Questa è un'operazione O(1), mentre prendere la lunghezza di una stringa in stile C è O(n).

Nei linguaggi che memorizzano la lunghezza come parte dell'oggetto stringa (C#, Java, ...) anche il controllo della lunghezza è O(1).In questo caso, il controllo diretto della lunghezza è più veloce, perché evita il sovraccarico legato alla costruzione della nuova stringa vuota.

In .Net:

string.IsNullOrEmpty( nystr );

le stringhe possono essere nulle, quindi .Length a volte lancia una NullReferenceException

Nelle lingue che utilizzano stringhe in stile C (con terminazione null), il confronto con "" sarà più veloce

In realtà, potrebbe essere meglio verificare se il primo carattere nella stringa è '\0':

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

In Perl c'è una terza opzione, ovvero che la stringa non è definita.Questo è leggermente diverso da un puntatore NULL in C, se non altro perché non si ottiene un errore di segmentazione per l'accesso a una stringa non definita.

In Java 1.6, la classe String ha un nuovo metodo è vuoto

C'è anche la biblioteca comune di Giakarta, che ha il file è vuoto metodo.Lo spazio vuoto è definito come una stringa che contiene solo spazi bianchi.

Supponendo che la tua domanda sia .NET:

Se vuoi convalidare la tua stringa anche contro la nullità usa IsNullOrEmpty, se sai già che la tua stringa non è nulla, ad esempio quando controlli TextBox.Text ecc., non usare IsNullOrEmpty, e poi arriva la tua domanda.
Quindi, a mio parere, String.Length ha prestazioni inferiori rispetto al confronto tra stringhe.

L'ho testato (ho provato anche con C#, stesso risultato):

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

Risultato:

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

Ciò significa che il confronto richiede molto più del semplice controllo della lunghezza della stringa.

String.IsNullOrEmpty() funziona solo su .net 2.0 e versioni successive, per .net 1/1.1, tendo a utilizzare:

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

Utilizzo String.Empty al contrario di "" perché "" creerà un oggetto, mentre String.Empty non lo farà: so che è qualcosa di piccolo e banale, ma preferisco comunque non creare oggetti quando non ne ho bisogno!(Fonte)

In realtà, IMO il modo migliore per determinare è il metodo IsNullOrEmpty() della classe string.

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

Aggiornamento:Supponevo che .Net, in altre lingue, potesse essere diverso.

In questo caso, il controllo diretto della lunghezza è più veloce, perché evita il sovraccarico legato alla costruzione della nuova stringa vuota.

@DerekPark:Non è sempre vero."" è una stringa letterale quindi, in Java, quasi sicuramente sarà già internata.

Per le corde di Do,

if (s[0] == 0)

sarà più veloce di entrambi

if (strlen(s) == 0)

O

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

perché eviterai il sovraccarico di una chiamata di funzione.

@Nathan

In realtà, potrebbe essere meglio verificare se il primo carattere nella stringa è '\0':

Ne avevo quasi parlato, ma ho finito per tralasciarlo, da quando ho chiamato strcmp() con la stringa vuota e controllando direttamente il primo carattere della stringa sono entrambi O(1).Fondamentalmente paghi solo per una chiamata di funzione extra, che è piuttosto economica.Se tu Veramente hai bisogno della migliore velocità in assoluto, tuttavia, scegli sicuramente un confronto diretto dal primo carattere a 0.

Onestamente lo uso sempre strlen() == 0, perchè ho Mai ho scritto un programma in cui questo era effettivamente un problema di prestazioni misurabile e penso che sia il modo più leggibile per esprimere il controllo.

Ancora una volta, senza conoscere la lingua, è impossibile dirlo.

Ti consiglio comunque di scegliere la tecnica che ha più senso per il programmatore di manutenzione che segue e dovrà mantenere il tuo lavoro.

Consiglierei di scrivere una funzione che faccia esplicitamente ciò che desideri, ad esempio

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

o comparabile.Ora non c'è dubbio che stai controllando.

Dopo aver letto questo thread, ho condotto un piccolo esperimento, che ha prodotto due risultati distinti e interessanti.

Considera quanto segue.

strInstallString    "1" string

Quanto sopra viene copiato dalla finestra delle impostazioni locali del debugger di Visual Studio.Lo stesso valore viene utilizzato in tutti e tre gli esempi seguenti.

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

Di seguito è riportato il codice visualizzato nella finestra di disassemblaggio del debugger di Visual Studio 2013 per questi due casi fondamentalmente identici.

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 ) non è significativamente diverso

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

Dagli elenchi di codici macchina sopra, generati dal modulo NGEN di .NET Framework, versione 4.5, traggo le seguenti conclusioni.

  1. Il test dell'uguaglianza rispetto alla stringa letterale vuota e alla proprietà statica string.Empty sulla classe System.string è, per tutti gli scopi pratici, identico.L'unica differenza tra i due frammenti di codice è l'origine della prima istruzione di movimento, ed entrambi sono offset relativi a ds, il che implica che entrambi si riferiscono a costanti integrate.

  2. Il test dell'uguaglianza rispetto alla stringa vuota, sia come valore letterale che come proprietà string.Empty, imposta una chiamata di funzione a due argomenti, che indica disuguaglianza restituendo zero.Baso questa conclusione su altri test che ho eseguito un paio di mesi fa, in cui ho seguito parte del mio codice attraverso il divario gestito/non gestito e ritorno.In tutti i casi, qualsiasi chiamata che richiedesse due o più argomenti inserisce il primo argomento nel registro ECX e il secondo nel registro EDX.Non ricordo come furono presentate le argomentazioni successive.Tuttavia, l'impostazione della chiamata assomigliava più a __fastcall che a __stdcall.Allo stesso modo, i valori di ritorno attesi venivano sempre visualizzati nel registro EAX, che è quasi universale.

  3. Il test della lunghezza della stringa imposta una chiamata di funzione ad un argomento, che restituisce 1 (nel registro EAX), che risulta essere la lunghezza della stringa da testare.

  4. Dato che il codice macchina immediatamente visibile è quasi identico, l'unica ragione che posso immaginare spiegherebbe la migliore prestazione dell'uguaglianza delle stringhe sulla lunghezza della puntura riportata da Brillante è che la funzione a due argomenti che esegue il confronto è ottimizzata in modo significativamente migliore rispetto alla funzione a un argomento che legge la lunghezza dall'istanza della stringa.

Conclusione

In linea di principio, evito il confronto con la stringa vuota come valore letterale, perché la stringa letterale vuota può apparire ambigua nel codice sorgente.A tal fine, le mie classi helper .NET definiscono da tempo la stringa vuota come costante.Anche se uso stringa.Empty per i confronti diretti e in linea, la costante guadagna il suo mantenimento per definire altre costanti il ​​cui valore è la stringa vuota, perché una costante non può essere assegnata stringa.Empty come il suo valore.

Questo esercizio risolve, una volta per tutte, ogni preoccupazione che potrei avere riguardo al costo, se del caso, del confronto con l'uno o l'altro stringa.Empty o la costante definita dalle mie classi di supporto.

Tuttavia, solleva anche la questione sconcertante di sostituirlo;perché sta confrontando contro stringa.Empty più efficiente che testare la lunghezza della stringa?Oppure il test utilizzato da Shinny è invalidato a causa del modo in cui viene implementato il loop?(Lo trovo difficile da credere, ma, ripeto, sono già stato ingannato in passato, come sono sicuro che sia successo anche a te!)

Lo suppongo da tempo system.string gli oggetti erano stringhe contate, fondamentalmente simili alla consolidata Basic String (BSTR) che conosciamo da tempo da COM.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top