Pregunta

¿Qué es más eficiente para el compilador y la mejor práctica para comprobar si una cadena está en blanco?

  1. Comprobando si la longitud de la cadena == 0
  2. Comprobando si la cadena está vacía (strVar == "")

Además, ¿la respuesta depende del idioma?

¿Fue útil?

Solución

Sí, depende del idioma, ya que el almacenamiento de cadenas difiere entre idiomas.

  • Cadenas tipo Pascal: Length = 0.
  • Cuerdas estilo C: [0] == 0.
  • .NETO: .IsNullOrEmpty.

Etc.

Otros consejos

En lenguajes que usan cadenas de estilo C (terminadas en nulo), en comparación con "" será más rápido.Esa es una operación O(1), mientras que tomar la longitud de una cadena estilo C es O(n).

En lenguajes que almacenan la longitud como parte del objeto de cadena (C#, Java, ...), la verificación de la longitud también es O(1).En este caso, comprobar directamente la longitud es más rápido porque evita la sobrecarga de construir la nueva cadena vacía.

En la red:

string.IsNullOrEmpty( nystr );

las cadenas pueden ser nulas, por lo que .Length a veces arroja una excepción NullReferenceException

En lenguajes que usan cadenas de estilo C (terminadas en nulo), la comparación con "" será más rápida

En realidad, puede ser mejor comprobar si el primer carácter de la cadena es '\0':

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

En Perl hay una tercera opción, que la cadena no esté definida.Esto es un poco diferente de un puntero NULL en C, aunque solo sea porque no obtienes un error de segmentación al acceder a una cadena indefinida.

En Java 1.6, la clase String tiene un nuevo método esta vacio

También está la biblioteca común de Yakarta, que tiene la está en blanco método.En blanco se define como una cadena que contiene solo espacios en blanco.

Suponiendo que su pregunta es .NET:

Si también desea validar su cadena contra la nulidad, use IsNullOrEmpty, si ya sabe que su cadena no es nula, por ejemplo, al verificar TextBox.Text, etc., no use IsNullOrEmpty, y luego viene su pregunta.
Entonces, en mi opinión, String.Length tiene menos rendimiento que la comparación de cadenas.

Lo probé (también lo probé con C#, mismo resultado):

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

Resultado:

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

Lo que significa que la comparación requiere mucho más que verificar la longitud de la cadena.

String.IsNullOrEmpty() sólo funciona en .net 2.0 y superiores, para .net 1/1.1, tiendo a usar:

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

Utilizo String.Empty en lugar de "" porque "" creará un objeto, mientras que String.Empty no lo hará. Sé que es algo pequeño y trivial, pero aún así prefiero no crear objetos cuando no los necesito.(Fuente)

En realidad, en mi opinión, la mejor manera de determinarlo es el método IsNullOrEmpty() de la clase de cadena.

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

Actualizar:Supuse que .Net, en otros idiomas, esto podría ser diferente.

En este caso, comprobar directamente la longitud es más rápido porque evita la sobrecarga de construir la nueva cadena vacía.

@DerekPark:Eso no siempre es cierto."" es una cadena literal, por lo que, en Java, es casi seguro que ya estará internada.

Para cuerdas C,

if (s[0] == 0)

será más rápido que cualquiera de los dos

if (strlen(s) == 0)

o

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

porque evitará la sobrecarga de una llamada a función.

@Natán

En realidad, puede ser mejor comprobar si el primer carácter de la cadena es '\0':

Casi mencioné eso, pero terminé omitiéndolo, ya que llamé strcmp() con la cadena vacía y verificando directamente que el primer carácter de la cadena sea O (1).Básicamente, solo pagas por una llamada de función adicional, que es bastante económica.Si usted en realidad Sin embargo, si necesita la mejor velocidad absoluta, definitivamente opte por una comparación directa del primer carácter a 0.

Sinceramente siempre uso strlen() == 0, porque yo tengo nunca Escribí un programa en el que esto era en realidad un problema de rendimiento medible, y creo que esa es la forma más legible de expresar el control.

Nuevamente, sin conocer el idioma, es imposible saberlo.

Sin embargo, te recomiendo que elijas la técnica que tenga más sentido para el programador de mantenimiento que seguirá y tendrá que mantener tu trabajo.

Recomiendo escribir una función que haga explícitamente lo que quieres, como

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

o comparable.Ahora no hay duda de que lo estás comprobando.

Después de leer este hilo, realicé un pequeño experimento que arrojó dos hallazgos distintos e interesantes.

Considera lo siguiente.

strInstallString    "1" string

Lo anterior se copia de la ventana local del depurador de Visual Studio.Se utiliza el mismo valor en los tres ejemplos siguientes.

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

A continuación se muestra el código que se muestra en la ventana de desensamblado del depurador de Visual Studio 2013 para estos dos casos fundamentalmente idénticos.

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

si ( strInstallString == string.Empty ) no es significativamente diferente

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

De los listados de código de máquina anteriores, generados por el módulo NGEN de .NET Framework, versión 4.5, saco las siguientes conclusiones.

  1. Las pruebas de igualdad con el literal de cadena vacía y la propiedad string.Empty estática en la clase System.string son, a todos los efectos prácticos, idénticas.La única diferencia entre los dos fragmentos de código es la fuente de la instrucción del primer movimiento, y ambos son desplazamientos relativos a ds, lo que implica que ambos se refieren a constantes integradas.

  2. Al probar la igualdad con la cadena vacía, ya sea como literal o como propiedad string.Empty, se configura una llamada de función de dos argumentos, que indica desigualdad devolviendo cero.Baso esta conclusión en otras pruebas que realicé hace un par de meses, en las que seguí parte de mi propio código a través de la división administrado/no administrado y viceversa.En todos los casos, cualquier llamada que requiera dos o más argumentos coloca el primer argumento en el registro ECX y el segundo en el registro EDX.No recuerdo cómo se aprobaron los argumentos posteriores.Sin embargo, la configuración de la llamada se parecía más a __fastcall que a __stdcall.Asimismo, los valores de retorno esperados siempre aparecían en el registro EAX, que es casi universal.

  3. Probar la longitud de la cadena configura una llamada a función de un argumento, que devuelve 1 (en el registro EAX), que resulta ser la longitud de la cadena que se está probando.

  4. Dado que el código de máquina inmediatamente visible es casi idéntico, la única razón que puedo imaginar explicaría el mejor rendimiento de la igualdad de cadenas a lo largo de la longitud de picadura informada por brillante es que la función de dos argumentos que realiza la comparación está significativamente mejor optimizada que la función de un argumento que lee la longitud de la instancia de cadena.

Conclusión

Como cuestión de principio, evito comparar con la cadena vacía como literal, porque la cadena literal vacía puede parecer ambigua en el código fuente.Con ese fin, mis clases auxiliares de .NET han definido durante mucho tiempo la cadena vacía como una constante.Aunque uso cadena.vacia para comparaciones directas en línea, la constante se mantiene para definir otras constantes cuyo valor es la cadena vacía, porque no se puede asignar una constante cadena.vacia como su valor.

Este ejercicio resuelve, de una vez por todas, cualquier inquietud que pueda tener sobre el costo, si lo hubiera, de comparar cualquiera de los dos. cadena.vacia o la constante definida por mis clases de ayuda.

Sin embargo, también plantea una cuestión desconcertante para reemplazarlo;¿Por qué se compara con cadena.vacia ¿Más eficiente que probar la longitud de la cuerda?¿O la prueba utilizada por Shinny se invalida porque, por cierto, se implementa el bucle?(Me resulta difícil de creer, pero, claro, ya me han engañado antes, ¡y estoy seguro de que a ti también!)

Durante mucho tiempo he asumido que sistema.cadena Los objetos eran cadenas contadas, fundamentalmente similares a la cadena básica (BSTR) establecida desde hace mucho tiempo que conocemos desde hace mucho tiempo de COM.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top