Página 2 de 2

Re: Métodos para contar las líneas de un archivo.

Publicado: 01 Sep 2011, 12:26
por Ximorro
¡Lo he hecho bastante más rápido!
Es probable que este tema ya esté abandonado, pero como ahora estábamos resolviendo otra duda con expresiones regulares me he acordado de esto... ¿y no se puede hacer esto con expresiones regulares? ¿será más rápido que el más rápido conseguido hasta ahora?

¡Pues y !
¡Y además el código es ultracorto!


Por ejemplo el código más rápido era el de Chefito con su proceso todo en AutoIt. En mi ordendor tarda algo más de un segundo. Ahora es el doble de rápido :smt003
Y busca todas las soluciones, porque Chefito, parece que el tuyo se deja algunas ¿? creo que las que tienen llaves "{" y "}" en el nombre.

El código es este, en la primera línea hay que cambiar la carpeta donde están los archivos. Tal como está busca el nombre como subcadena, es decir, si se busca 'Mamba Edge' también encuentra 'Mamba Edge - Haste', por ejemplo. En realidad buscar el nombre exacto es más sencillo, os lo pongo después, pero como hasta ahora parece que buscabais subcadenas pues el inicial es este:

Código: Seleccionar todo

$dir = "C:\temp\items\"

$hBusq = FileFindFirstFile($dir & "*.txt")

If $hBusq = -1 Then
	MsgBox(16, "Error buscando archivos", "No se encontraron los archivos TXT en la carpeta: " & @CRLF & $dir)
	Exit
EndIf

;$txtBusc = 'Short Sword' ;el primero
;$txtBusc = 'Diadem' ; el medio
;$txtBusc = 'Rabbit Ear' ;el último
$txtBusc ='Mamba Edge'

While 1
	$nomFich = FileFindNextFile($hBusq)
	If @error Then ExitLoop ; Se han acabado los archivos

	$texto=FileRead($dir & $nomFich)
	If @error Then
		MsgBox(0, "Error", "Error leyendo: " & @CRLF & $nomFich)
		Exit
	EndIf
	$res = StringRegExp($texto, '(?U)<item id="(.*)".*name="(.*' & $txtBusc & '.*)">', 3)
	For $i = 0 To UBound($res)/2-1
		ConsoleWrite($nomFich & " -> ID: " & $res[$i*2] & " - NOMBRE: " & $res[$i*2+1] & @CRLF)
	Next
WEnd
FileClose($hBusq)
Así para 'Mamba Edge' en medio segundo me encuentra:

Código: Seleccionar todo

15500-15599.txt -> ID: 15545 - NOMBRE: Mamba Edge
15800-15899.txt -> ID: 15874 - NOMBRE: Mamba Edge - Haste
15800-15899.txt -> ID: 15875 - NOMBRE: Mamba Edge - Crt. Damage
15800-15899.txt -> ID: 15876 - NOMBRE: Mamba Edge - HP Drain
15900-15999.txt -> ID: 15914 - NOMBRE: Mamba Edge {PvP}
15900-15999.txt -> ID: 15986 - NOMBRE: Mamba Edge {PvP} - Haste
15900-15999.txt -> ID: 15987 - NOMBRE: Mamba Edge {PvP} - Crt. Damage
15900-15999.txt -> ID: 15988 - NOMBRE: Mamba Edge {PvP} - HP Drain
16100-16199.txt -> ID: 16156 - NOMBRE: Mamba Edge Dual Daggers
16100-16199.txt -> ID: 16157 - NOMBRE: Mamba Edge Dual Daggers {PvP}
Si buscamos el nombre exacto es cosa de cambiar la expresión regular y la extracción de resultados con:

Código: Seleccionar todo

	$res = StringRegExp($texto, '(?U)<item id="(.*)".*name="' & $txtBusc & '">', 3)
	For $i = 0 To UBound($res)-1
		ConsoleWrite($nomFich & " -> ID: " & $res[$i] & @CRLF)
	Next
De todas maneras igual hay que buscar en todos los archivos porque hay items con exactamente el mismo nombre, por ejemplo para $txtBusc = "Artisan's Goggles" me encuentra dos:
Item:Artisan's Goggles
08100-08199.txt -> ID: 8186
22100-22199.txt -> ID: 22172

Re: Métodos para contar las líneas de un archivo.

Publicado: 01 Sep 2011, 14:54
por Chefito
Ximorro escribió:¡Lo he hecho bastante más rápido!Es probable que este tema ya esté abandonado, pero como ahora estábamos resolviendo otra duda con expresiones regulares me he acordado de esto... ¿y no se puede hacer esto con expresiones regulares? ¿será más rápido que el más rápido conseguido hasta ahora?
Sí, los he probado y va casi siempre va el doble de rápido que el que yo hice :smt023 .
Ximorro escribió:¡Y además el código es ultracorto!
Hombre, el mío ocupa lo que el tuyo :smt005 . Lo que pasa que te parecería más largo por la función de contar líneas (por lo que veo, puede que con expresiones regulares sea más rápida esta función :smt005 ). Pero da igual, la velocidad es lo que vale. Da igual el tamaño. Y en eso, por lo visto, las expresiones regulares son las campeonas. Que raro que no se nos ocurriese en su momento :smt003 .
Ximorro escribió:Por ejemplo el código más rápido era el de Chefito con su proceso todo en AutoIt. En mi ordendor tarda algo más de un segundo. Ahora es el doble de rápido Y busca todas las soluciones, porque Chefito, parece que el tuyo se deja algunas ¿? creo que las que tienen llaves "{" y "}" en el nombre.
No se deja ninguna. Si te fijas está programado así. Cuando encuentra una coincidencia en un archivo deja de buscar más en ese archivo. Se supone que el texto a buscar tenía que ser único no? Lo que pasa que supuse que estabamos poniendo cualquier texto de ejemplo. Las expresiones regulares buscan todas las coincidencias en esos archivos, por eso salen más.

El código es practicamente el mismo, lo único que cambia es que uno utiliza la función StringInStr y el otro StringRegExp. Si te digo la verdad, yo entre las dos hubiese apostado con que era más rápida StringInStr, ya que a primera vista parece que hace menos cosas que la expresión regular. Pero parece ser que no. Pensaba que comparar una cadena fija de texto iba a ser más rápido que comparar con una expresión regular. Que pienso que significa esto? Pues que StringInStr puede que esté peor definida que StringRegExp. O que utilice algún método más lento o más antiguo. Cualquiera sabe.

Me gustaría probar estas dos funciones en otros lenguajes a ver si en autoit está peor definida :smt003 . Puede que algún día lo intente con vb.net a ver quien gana en ese lenguaje :smt020 .

En definitiva, el codigo de Ximorro es el vencedor!!! :smt023 .

Con esto hemos descubierto algo muy muy importante. Que en búsquedas de textos hay que intentar utilizar expresiones regulares para ganar velocidad. Por poner un ejemplo, tendría que variar el programa que hice de búsqueda de texto en la búsqueda de texto plano, ya que lo hago on stringinstr :smt005 .

Saludos.

Re: Métodos para contar las líneas de un archivo.

Publicado: 02 Sep 2011, 08:04
por Ximorro
Pero es que lo de contar líneas hay que tenerlo en cuenta porque si te fijas la expresión regular no es sólo para saber si el item está en el archivo, sino que a la vez recoge el ID, que es lo que quiere encontrar Haseo.
No habría que pasar eso a expresión regular, es que ya está integrado.
La verdad es que no es exactamente el mismo proceso, porque tú buscas el número de línea, que es lo que Haseo pedía, y yo el ID, que es lo que Haseo quería ;-)

¿Cuando encuentras una coincidencia en un archivo dejas de buscar más en ese archivo? No me había fijado, qué tramposo :smt005 :smt043
De hecho eso es lo que supuse al principio, que el Item era único, por eso yo no sólo paraba de buscar en el archivo, paraba de buscar en TODOS los archivos. Si es único, es único para todos...
En cualquier caso he comprobado que no son únicos, incluso con exactamente el mismo nombre (no como subcadena del nombre) hay items con diferente ID. Así que mejor buscarlos todos.

Creo que StringInStr es más lenta porque hace más cosas, o mejor dicho, StringInStr y StringRegExp hacen cosas diferentes, pero se pueden usar ambas para buscar cadenas exactas. StringRegExp hace más cosas con patrones y StringInStr por ejemplo busca hacia atrás, cosa que creo que la otra no hace (la función no lo hace, y que yo sepa no se puede especificar en la ER, aunque eso nunca se sabe, ¡son tan complicadas!)

Pero es un tema interesante, haré pruebas comparativas y os postearé los resultados.

Y bueno, no gano yo, si acaso las expresiones regulares :smt027