Expresion regular para filtrar una búsqueda

Iniciado por LeandroA, 29 Agosto 2010, 15:47 PM

0 Miembros y 2 Visitantes están viendo este tema.

LeandroA

Hola, estoy intentando resolver lo siguiente, si se fijan en la búsqueda de windows utiliza cierta expresiones para resolver la búsqueda por ejemplo si ingresamos

Citarcasa *.bmp

Nos devuelve todos los archivos .bmp y cualquier tipo de archivo que contenga la palabra casa

Citar
*.jpg *.bmp

Nos devuelve todos los archivos .bmp y .jpg

Citar???.bmp

Nos devuelve todos los archivos .bmp de 3 letras por ejemplo "Cut.bmp" "New.bmp"

Citarar*.bmp

nos devuelve todos los archivos .bmp que comienzen con "ar"


que tipo de expresión regular debería implementar para poder cumplir esas condiciones

intento hacer una función parecida a esta

Private Function IsInFilter(ByVal sFilter As String, ByVal sMatch As String) As Boolean
'-------
End Function



Debug.Print IsInFilter("*.bmp ????.jpg", "foto.png")

Gracias

Psyke1

#1
Hola LeandroA!!
Mira, te hice un ejemplo (Creo que es similar a lo que buscas):

Código (vb) [Seleccionar]
Option Explicit

Public Function Get_Extensions_Files(ByVal sText As String, ByVal sPatern As String) As Collection
Dim cTemp                               As New Collection
Dim oRegExp                             As Object
Dim oMatch                              As Object
Dim oMatches                            As Object
   '# Para evitar las referencias :P
   Set oRegExp = CreateObject("VBScript.RegExp")
   
   With oRegExp
       .Pattern = sPatern
       .Global = True
       .IgnoreCase = True
   End With
   Set oMatches = oRegExp.Execute(sText)
   
   For Each oMatch In oMatches
       cTemp.Add oMatch.Value
   Next
   
   Set Get_Extensions_Files = cTemp
End Function


Un ej:
Código (vb) [Seleccionar]
Private Sub Form_Load()
   Dim vItem               As Variant
   Dim sStringtoAnalyze    As String

   sStringtoAnalyze = "Hola, esto es un ejemplo LeandroA.jpg para que veas que funciona Mi_foto.jpg"
   For Each vItem In Get_Extensions_Files(sStringtoAnalyze, "(\S)+\.jpg")
       Debug.Print vItem
   Next
End Sub


Resultado:
Citar
LeandroA.jpg
Mi_foto.jpg

PD: Si tienes problemas, se puede mejorar la Expresion Regular, te lo he hecho "a lo rapido" :P

Espero haberte ayudado ;)

DoEvents¡! :P

EDIT:

Para sacar jpg y bmp:
((\S)+\.(jpg|bmp))


????.jpg es igual a:
(\S{4}\.jpg)

ar*.jpg equivale a :
(ar(\S)*\.jpg)


raul338

#2
Contestare en forma rapida, no dispongo de mucho tiempo. Al final tuve tiempo de mas y experimente un poco  ;)

lo que hay que hacer es reemplazar los filtros antes de pasarlos por expresiones regulares:

Reemplazar los puntos "." por "\."
Los comodines "?" representan un solo caracter: .
Los comodines "*" representan mas de un caracter: .+

Por lo que quedarian los filtros asi
Citar

casa *.bmp
casa .+\.bmp




???.bmp
...\.bmp




ar*.bmp
ar.+\.bmp

Hay un problema con este filtro
*.jpg *.bmp
si fuera por reemplazo quedaria asi
.+\.jpg .+\.bmp
pero eso no devolvera los valores esperados, ya que ninguno devolvera true salvo que sea bmp con ".jpg" en su nombre :P

Asi que si en caso fuera asi, habria que probar antes si el filtro concuerda con esta expresion regular
((?:\*|\?+)\.\w+\s?)+
La contra de este filtro es que no se va a poder mezclar con otros filtros... por lo que quedaria (codigo al vuelo, es muy probable de que tire algun error)

Código (vb) [Seleccionar]

' Basado en el de PySkE1
Public Function IsInFilter(ByVal sPatern As String, ByVal sText As String) As Boolean
Dim cTemp                               As New Collection
Dim oRegExp                             As Object
Dim oMatch                              As Object
Dim oMatches                            As Object
Dim i As Integer
   '# Para evitar las referencias :P
   Set oRegExp = CreateObject("VBScript.RegExp")
   With oRegExp
       .Pattern = "(\*|\?+)\.\w+"
       .Global = True
       .IgnoreCase = True
   End With
   Set oMatches = oRegExp.Execute(sPatern)
   
   sPatern = ReplaceFilter(sPatern)
   
   If oMatches.Count > 0 Then
       For Each oMatch In oMatches
           cTemp.Add oMatch.Value
       Next
       
       Dim vItem As Variant
       For Each vItem In cTemp
           vItem = ReplaceFilter(CStr(vItem))
           oRegExp.Pattern = vItem
           Set oMatches = oRegExp.Execute(sText)
           If oMatches.Count > 0 Then
               IsInFilter = True
               Exit Function
           End If
       Next
   Else
       oRegExp.Pattern = sPatern
       Set oMatches = oRegExp.Execute(sText)
       If oMatches.Count > 0 Then
           IsInFilter = True
           Exit Function
       End If
   End If
End Function

Public Function ReplaceFilter(Filtro As String) As String
   Filtro = Replace(Filtro, ".", "\.")
   Filtro = Replace(Filtro, "*", ".+")
   ReplaceFilter = Replace(Filtro, "?", ".")
End Function


Código (vb) [Seleccionar]

Private Sub Form_Load()
   Debug.Print IsInFilter("a.jpg", "?.jpg")
   Debug.Print IsInFilter("foto.jpg", "*.jpg")
   Debug.Print IsInFilter("foto.jpg", "*.jpg *.bmp")
   Debug.Print IsInFilter("foto.bmp", "*.jpg *.bmp")
   Debug.Print IsInFilter("cualquiera.blend", "*.jpg *.bmp")
End Sub


Espero que te sirva! :P

Psyke1

Exacto raul338!!  ;-)
Ahora si que si... :D
Tambien pense algo asi, pero me pudo la vagancia... :silbar: :laugh:

DoEvents¡! :P



LeandroA

hola gracias a ambos, en realidad es mas complicado de lo que parece.

hice un par de pruebas y no esta correcto.

MsgBox IsInFilter("*.bmp *jpg", "foto.bmp") = falso ( es verdadero)

MsgBox IsInFilter("*.bmp ????.jpg", "foto.jpg") = falso ( es verdadero)

MsgBox IsInFilter("*.bmp", "foto.bmp")  = falso ( es verdadero)

no se si se entendio bien
el usuario en la busqueda tipea "*.bmp ????.jpg" luego a medida que se realiza la busqueda iran pasando una series de archivos por la funcion.
Por ejemplo "calc.exe", "documento.doc", "Mi foto.bmp" etc. etc.

ejemplos correctos

"*.bmp; *.jpg *.png" este ejemplo lista todos los .bmp, .jpg, .png que pasen por la funcion  (y notece que ensima en una parte puse ";" y en otra no)

"a?????.bmp" este por ejmplo va a filtrar todos .bmp los que comienzen con a y tengan cinco letras intermedias "Azteca.bmp" "active.bmp"

bueno el mejor ejemplo esta en la busqueda de windows si buscan algo veran como trabaja.

SAludos


raul338

#5
Cita de: LeandroA en 29 Agosto 2010, 20:20 PM
hice un par de pruebas y no esta correcto.

MsgBox IsInFilter("*.bmp *jpg", "foto.bmp") = falso ( es verdadero)

MsgBox IsInFilter("*.bmp ????.jpg", "foto.jpg") = falso ( es verdadero)

MsgBox IsInFilter("*.bmp", "foto.bmp")  = falso ( es verdadero)

no se si se entendio bien

Leandro... no se si te diste cuenta, pero, lo estas usando al revez  :xD
De todas formas, cambiando el orden los parametros (o la firma) tiran true  ;D
Ahi cambie la firma en el codigo anterior...

LeandroA

#6
Que bruto que soy, tenes razón no me habia dado cuenta que están cambiado los parámetros jejeje

buenisimo funciona de lujo. :laugh: :laugh:

este quizas no tira correcto

MsgBox IsInFilter("a?????.bmp", "Azteca.bmp") = true

MsgBox IsInFilter("a?????.bmp", "Aztsdfdfdseca.bmp") = true

la segunda deberia ser false, voy a ver si me sale algo

raul338

Cita de: LeandroA en 29 Agosto 2010, 20:31 PM
MsgBox IsInFilter("a?????.bmp", "Aztsdfdfdseca.bmp") = true
deberia ser false

Cita de: raul338 en 29 Agosto 2010, 18:15 PM
Asi que si en caso fuera asi, habria que probar antes si el filtro concuerda con esta expresion regular
((?:\*|\?+)\.\w+\s?)+
La contra de este filtro es que no se va a poder mezclar con otros filtros... por lo que quedaria (codigo al vuelo, es muy probable de que tire algun error)

Jajaja toy quedando re pesado seguro, pero es lo que se me ocurrio a mi, la solucion, cambiar la expresion regular :P pero.... ahora no tengo tiempo (apenas me paso de a ratos por aca)
De todas formas, debe ser simple el reemplazo, capaz agregando un \w+ o .+ en el medio :P

Psyke1

#8
Os dejo esta funcion por si ayuda... ;)

Código (vb) [Seleccionar]
Public Function ReplaceFilter(ByVal Filtro As String) As String
Dim x                           As Integer
Dim n                           As Integer
Dim sActualChar                 As String
   x = 1 : n = 1
   Do Until x > Len(Filtro)
       sActualChar = Mid$(Filtro, x, 1)
       If sActualChar = "?" Then
           Do While Mid$(Filtro, x + 1, 1) = "?"
               n = n + 1
               x = x + 1
           Loop
           sActualChar = ".{" & n & "}"
           n = 1
       ElseIf sActualChar = "." Then
           sActualChar = "\."
       End If
       ReplaceFilter = ReplaceFilter + sActualChar
       x = x + 1
   Loop
   ReplaceFilter = Replace$(ReplaceFilter, "*", ".+")
   ReplaceFilter = Replace$(ReplaceFilter, " ", "|")
   ReplaceFilter = "(" & ReplaceFilter & ")"
End Function


Un ejemplo:
Código (vb) [Seleccionar]
Private Sub Form_Load()
   MsgBox ReplaceFilter("a*.jpg ????.bmp")
End Sub


Me devuelve:
Citar(a.+\.jpg|.{4}\.bmp)

Te da la Expresion Regular toda bonita  ::)

DoEvents¡! :P

EDITO: Se me ocurre otra forma de hacerlo, mañana posteo.. :)

Psyke1

#9
Bueno, no me pude aguantar, aqui tienes LeandroA  ;):

Código (vb) [Seleccionar]

Option Explicit

Public Function IsInFilter(ByVal sText As String, ByVal sPatern As String) As Boolean
Dim oRegExp                             As Object
Dim oMatches                            As Object
   Set oRegExp = CreateObject("VBScript.RegExp")
   sText = " " & sText
   sPatern = ReplaceFilter(sPatern)
   With oRegExp
       .Pattern = sPatern
       .Global = True
       .IgnoreCase = True
   End With
   Set oMatches = oRegExp.Execute(sText)
   IsInFilter = CBool(oMatches.Count)
End Function

Public Function ReplaceFilter(ByVal sFilter As String) As String
Dim x                                   As Integer
Dim n                                   As Integer
Dim sActualChar                         As String
   x = 1: n = 1
   Do Until x > Len(sFilter)
       sActualChar = Mid$(sFilter, x, 1)
       If sActualChar = "?" Then
           Do While Mid$(sFilter, x + 1, 1) = "?"
               n = n + 1
               x = x + 1
           Loop
           sActualChar = ".{" & n & "}"
           n = 1
       ElseIf sActualChar = "." Then
           sActualChar = "\."
       End If
       ReplaceFilter = ReplaceFilter + sActualChar
       x = x + 1
   Loop
   ReplaceFilter = Replace$(ReplaceFilter, "*", ".+")
   ReplaceFilter = Replace$(ReplaceFilter, " ", "|")
   If Left$(sFilter, 1) = "?" Then
       ReplaceFilter = "(\s" & ReplaceFilter & ")"
   Else
       ReplaceFilter = "(" & ReplaceFilter & ")"
   End If
End Function

' OffTopic : "Vivan las ranas¡!"
Private Sub Form_Load()
   Debug.Print IsInFilter("holal.jpg", "?????.jpg")    'True
   Debug.Print IsInFilter("a.jpg", "?.jpg")            'true
   Debug.Print IsInFilter("foto.jpg", "*.jpg")         'True
   Debug.Print IsInFilter("foto.jpg", "*.jpg *.bmp")   'True
   Debug.Print IsInFilter("foto.bmp", "*.jpg *.bmp")   'True
   Debug.Print IsInFilter("cualquiera.blend", "*.jpg *.bmp") 'False
   ' Los ejemplos que pusiste
   Debug.Print IsInFilter("Azteca.bmp", "a?????.bmp") 'True
   Debug.Print IsInFilter("Aztsdfdfdseca.bmp", "a?????.bmp") 'False
End Sub


Me devuelve:
Citar
Verdadero
Verdadero
Verdadero
Verdadero
Verdadero
Falso
Verdadero
Falso
::)

DoEvents¡! :P