2011-06-23 13 views
9

Me gustaría escribir una función/módulo de utilidad que proporcione una combinación de comodín/comodín simple para las cadenas. La razón por la que no estoy usando expresiones regulares es que el usuario será quien termine proporcionando los patrones para que coincidan utilizando algún tipo de archivo de configuración. No pude encontrar ninguna gema que sea estable: intenté con el comodín pero tuve problemas para configurarlo.Coincidencia de cadena de caracteres comodín en Ruby

La funcionalidad que estoy buscando es simple. Por ejemplo, dados los siguientes patrones, aquí están las coincidencias:

pattern | test-string   | match 
========|=====================|==================== 
*hn  | john, johnny, hanna | true , false, false  # wildcard , similar to /hn$/i 
*hn* | john, johnny, hanna | true , true , false  # like /hn/i 
hn  | john, johnny, hanna | false, false, false  # /^hn$/i 
*h*n* | john, johnny, hanna | true , true , true 
etc... 

Me gustaría que esto sea lo más eficiente posible. Pensé en crear expresiones regulares a partir de las cadenas de patrones, pero parecía bastante ineficiente de hacer en tiempo de ejecución. ¿Alguna sugerencia sobre esta implementación? Gracias.

EDITAR: estoy usando ruby ​​1.8.7

Respuesta

13

no veo por qué crees que sería ineficiente Las predicciones sobre este tipo de cosas son notoriamente poco confiables, debe decidir que es demasiado lento antes de ir hacia atrás para encontrar una manera más rápida. Y luego debe perfilarlo para asegurarse de que aquí es donde radica el problema (por cierto hay un aumento promedio de 3-4x de velocidad al cambiar a 1.9)

De todos modos, debería ser bastante fácil hacer esto, algo así como :

class Globber 
    def self.parse_to_regex(str) 
    escaped = Regexp.escape(str).gsub('\*','.*?') 
    Regexp.new "^#{escaped}$", Regexp::IGNORECASE 
    end 

    def initialize(str) 
    @regex = self.class.parse_to_regex str 
    end 

    def =~(str) 
    !!(str =~ @regex) 
    end 
end 


glob_strs = { 
    '*hn' => [['john', true, ], ['johnny', false,], ['hanna', false]], 
    '*hn*' => [['john', true, ], ['johnny', true, ], ['hanna', false]], 
    'hn'  => [['john', false,], ['johnny', false,], ['hanna', false]], 
    '*h*n*' => [['john', true, ], ['johnny', true, ], ['hanna', true ]], 
} 

puts glob_strs.all? { |to_glob, examples| 
    examples.all? do |to_match, expectation| 
    result = Globber.new(to_glob) =~ to_match 
    result == expectation 
    end 
} 
# >> true 
+0

creo que en el caso de ' '* hn'' por ejemplo, que necesita'' John es awesome'' para que también sea verdadero, y con '/.* hn $ /' no coincidirá con –

+0

No parece ser la forma en que los globs funcionan en mi computadora (Mac OSX Leopard) https://gist.github.com/1041942 –

+0

I supongo que el comodín es más preciso que glob para mi propósito - para el caso de ''* hn'' me gustaría e todo antes y después del patrón para que coincida, y nada después; tan 'verdadero' para' 'john'',' falso' para ''john es ..''. gracias – sa125

1
def create_regex(pattern) 
if pattern[0,1] != '*' 
    pattern = '[^\w\^]' + pattern 
end 
if pattern[-1,1] != '*' 
    pattern = pattern + '[^\w$]' 
end 
return Regexp.new(pattern.gsub(/\*/, '.*?')) 
end 

Este methoid debe devolver su expresión regular

PD: no se prueba: D

+2

hacer algo de edición - gracias por señalar los errores de sintaxis - demasiada perl/php: D –

Cuestiones relacionadas