Соответствие строки подстановочного знака в Ruby - PullRequest
10 голосов
/ 23 июня 2011

Я хотел бы написать служебную функцию / модуль, который будет обеспечивать простой подстановочный знак / глобальное сопоставление со строками.Причина, по которой я не использую регулярные выражения, заключается в том, что именно пользователь в конечном итоге предоставит шаблоны для сопоставления с использованием какого-либо файла конфигурации.Я не смог найти такой стабильный камень - попробовал джокер, но у него были проблемы с настройкой.

Функциональность, которую я ищу, проста.Например, учитывая следующие шаблоны, вот совпадения:

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...

Я бы хотел, чтобы это было максимально эффективно.Я думал о создании регулярных выражений из строк шаблона, но это казалось довольно неэффективным во время выполнения.Любые предложения по этой реализации?спасибо.

РЕДАКТИРОВАТЬ : я использую ruby ​​1.8.7

Ответы [ 2 ]

13 голосов
/ 23 июня 2011

Я не понимаю, почему вы думаете, что это будет неэффективно. Предсказания о таких вещах общеизвестно ненадежны, вы должны решить, что это слишком медленно, прежде чем вы наклонитесь назад, чтобы найти более быстрый путь. И затем вы должны профилировать его, чтобы убедиться, что именно в этом и заключается проблема (кстати, в среднем увеличение скорости в 3-4 раза от переключения на 1,9)

В любом случае, это должно быть довольно легко сделать, что-то вроде:

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
1 голос
/ 23 июня 2011
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

Этот метод должен вернуть ваше регулярное выражение

PS: он не проверен: D

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...