2012-01-17 12 views
6

¿Cómo se compara el rendimiento de estas dos formas de determinar si una cadena comienza con una determinada subcadena en Delphi? ¿Es uno significativamente más rápido/más eficiente que el otro?Eficiencia de las técnicas de "comienza con subcadena" en Delphi?

if ((testString[1] = '=') AND (testString[2] = '?')) then ... 

vs

if (AnsiStartsStr('=?', testString)) then ... 
+4

Evaluación de izquierda a derecha no se requiere para el primer método. Puede ajustarlo para filtrar primero las ocurrencias menos frecuentes. Por ejemplo, podría probar primero el signo de interrogación si fuera menos frecuente. –

Respuesta

7

Bueno, lo primero será definitivamente más rápido. Resolver un problema altamente codificado y altamente específico casi siempre es mucho más rápido que pasar una solución específica a una rutina de resolución de problemas generales. En cuanto a "significativamente" más rápido, ¿por qué no lo pruebas? Ejecute ambas versiones en un bucle 10 millones de veces y use TStopwatch (o algo más si no tiene D2010 o posterior) para medir el tiempo.

Una cosa más: la primera es definitivamente más rápida, pero también podría ser incorrecta. Si no se garantiza que length(TestString) sea> = 2, podría tener una condición de error aquí. Si TestString es una cadena vacía, esto generará una excepción. De lo contrario, puede o no obtener una excepción dependiendo de la configuración del compilador.

+2

Buen punto. El primero no siempre es seguro. Al menos necesita 'if Length (testString)> = 2) y ...' –

+1

La evaluación de cortocircuitos de AND también es una gran ayuda, en casos donde no coincida. –

+0

@MarcusAdams Si descuidó el aspecto LOCALE de 'AnsiStartsStr', entonces' AnsiStartsStr' podría implementarse tan eficientemente como el 'if' explícito (aunque ciertamente no lo es) –

2

La primera en la ventana de la CPU es sólo mov, cmp y jnz (con el tiempo se repite una vez), mientras que la segunda se ve mucho más complicado (utiliza Copy y Winapi de CompareString). Primero debería ser más rápido.

+0

'AnsiStartsStr()' utilizando 'Copiar()' internamente es una mala implementación por parte de Borland, en mi humilde opinión. Podrían haber usado 'CompareString()' sin 'Copy()' como 'AnsiStartsText()', simplemente llama a 'CompareString()' con diferentes banderas. Lástima que CodeGear y Embarcadero nunca arreglaron eso durante los años posteriores a que Borland renunciara a la propiedad de sus herramientas de desarrollo. –

+0

@ RemyLebeau-TeamB El cuello de botella principal de 'AnsiStartsStr' no es el uso interno de' copia', sino el uso de 'AnsiSameStr' que llama a la lenta API' CompareString' de Windows. De hecho, la mayoría de las funciones 'Ansi *' llaman a esas API y son lentas si no es necesario el manejo completo de Unicode (por ejemplo, cuando se utilizan caracteres Ascii de 7 bits, lo que sucede mucho en la programación). El RTL completo está lleno de código de trabajo, pero no está escrito para la velocidad. Mi favorito es la implementación de 'IntToStr', que es muy lenta (incluso más lenta desde Delphi 2009). –

4

Si necesita velocidad con la flexibilidad que usted puede intentar algo como:

function StatsWith(const SubStr, Str: string): Boolean; inline; 
begin 
    if Length(SubStr) <= Length(Str) then 
    Result := CompareMem(Pointer(SubStr), Pointer(Str), ByteLength(SubStr)) 
    else 
    Result := False; 
end; 
+0

ByteLength() funcionará con Delphi 2009+ solo sospecho. 'length (SubStr) * sizeof (char)' es más estándar. –

+1

@ArnaudBouchez Si no tiene intención de soportar versiones anteriores del compilador, entonces 'ByteLength' es más claro. –

+0

ByteLength se implementa (en D2010) como una función en línea que se implementa como 'Longitud (s) * SizeOf (Char)' ... De todos modos, eso podría ser exagerado, pero probablemente vaya con 'Longitud (s) * StringElementSize (s) '. –

Cuestiones relacionadas