Controllo del contenuto della stringa?lunghezza della stringa rispetto alla stringa vuota
-
08-06-2019 - |
Domanda
Qual è la soluzione più efficiente per il compilatore e la procedura migliore per verificare se una stringa è vuota?
- Verifica se la lunghezza della stringa == 0
- Verifica se la stringa è vuota (strVar == "")
Inoltre, la risposta dipende dalla lingua?
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.
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.
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.
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.
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.
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.