Более понятный способ разбора токена из строки в ruby - PullRequest
1 голос
/ 21 мая 2009

Я пытаюсь что-то очистить, черт возьми, и ищу какие-то лучшие способы сделать это. Идея состоит в том, что вместо использования регулярных выражений в моих правилах для синтаксического анализа строки, я хотел бы использовать что-то ближе к синтаксису маршрутов "thing /: searchitem / somethingelse ", а затем дать строку типа" /thing / FOUNDIT /thingelse " "вы получите результат" FOUNDIT ".

Вот пример, который я рефакторинг: С учетом входной строки произнесите «http://claimid.com/myusername".. Я хочу иметь возможность запустить эту строку для нескольких возможных совпадений, а затем вернуть« myusername »для того, которое совпадает.

Данные для запуска могут выглядеть так:

PROVIDERS = [
  "http://openid.aol.com/:username",
  "http://:username.myopenid.com",
  "http://claimid.com/:username",
  "http://:username.livejournal.com"]

  something_here("http://claimid.com/myusername") # => "myusername" 

Есть ли хороший способ сопоставить строку, подобную http://claimid.com/myusername, с этим списком и понять смысл результатов? Или какие-нибудь методы, чтобы сделать что-то подобное легче? Я просматривал код маршрутизации rails, как он делает что-то вроде этого, но это не самый простой код для подражания.


Сейчас я просто делаю это с помощью регулярных выражений, но кажется, что приведенный выше метод будет НАМНОГО проще читать

PROVIDERS = [
  /http:\/\/openid.aol.com\/(\w+)/,
  /http:\/\/(\w+).myopenid.com/,
  /http:\/\/(\w+).livejournal.com/,
  /http:\/\/flickr.com\/photos\/(\w+)/,
  /http:\/\/technorati.com\/people\/technorati\/(\w+)/,
  /http:\/\/(\w+).wordpress.com/,
  /http:\/\/(\w+).blogspot.com/,
  /http:\/\/(\w+).pip.verisignlabs.com/,
  /http:\/\/(\w+).myvidoop.com/,
  /http:\/\/(\w+).pip.verisignlabs.com/,
  /http:\/\/claimid.com\/(\w+)/]

url = "http://claimid.com/myusername"
username = PROVIDERS.collect { |provider|
  url[provider, 1]
}.compact.first

Ответы [ 4 ]

4 голосов
/ 21 мая 2009

Я думаю, что вам лучше всего генерировать регулярные выражения, как ранее предлагал Элазар. Если вы просто сопоставляете одно поле (: username), то что-то вроде этого будет работать:

PROVIDERS = [
   "http://openid.aol.com/:username/",
   "http://:username.myopenid.com/",
   "http://:username.livejournal.com/",
   "http://flickr.com/photos/:username/",
   "http://technorati.com/people/technorati/:username/",
   "http://:username.wordpress.com/",
   "http://:username.blogspot.com/",
   "http://:username.pip.verisignlabs.com/",
   "http://:username.myvidoop.com/",
   "http://:username.pip.verisignlabs.com/",
   "http://claimid.com/:username/"
]

MATCHERS = PROVIDERS.collect do |provider|
  parts = provider.split(":username")
  Regexp.new(Regexp.escape(parts[0]) + '(.*)' + Regexp.escape(parts[1] || ""))
end

def extract_username(url)
  MATCHERS.collect {|rx| url[rx, 1]}.compact.first
end

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

2 голосов
/ 21 мая 2009

Как насчет String include? или index?

url.include? "myuserid" 

Или вы хотите какую-нибудь позиционную вещь? Если это так, то вы можете split URL.

Да, третья мысль: используя вашу форму ввода с: username thing, создайте и скомпилируйте регулярное выражение для каждой такой строки и используйте Regexp # match , чтобы получить MatchData Если вы сохранили пары регулярных выражений и индекса поля: username, вы можете сделать это напрямую.

1 голос
/ 21 мая 2009

Это немного специфично для URI, но в стандартной библиотеке есть URI.split ():

require 'uri'

URI.split("http://claimid.com/myusername")[5] # => "/myusername"

Может быть, каким-то образом это использовать.

C.J.

1 голос
/ 21 мая 2009

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

class Router
    def initialize(routing_word)
        @routes = routing_word.scan /:\w+/
        @regex = routing_word
        @regex.gsub!('/','\\/')
        @regex = Regexp.escape(@regex)
        @regex.gsub!(/:\w+/,'(\w+)')
            @regex = '^'+@regex+'$'
        @regex = Regexp.new(@regex)
    end
    def match(url)
        matches = url.match @regex
        ar = matches.to_a[1..-1]
        h = {}
        @routes.zip(ar).each {|k,v| h[k] = v}
        return h
    end
end

r = Router.new('|:as|:sa')
puts r.match('|a|b').map {|k,v| "#{k} => #{v}\n"}

Используйте маршрутизатор для каждой строки маршрутизации. Он должен возвращать хорошие хеш-таблицы, которые соответствуют строковым двоеточиям URL фактическим компонентам URL.

Чтобы распознать данный URL-адрес, необходимо пройти через все маршрутизаторы и выяснить, какой из них принимает данный URL-адрес.

class OpenIDRoutes
    def initialize()
        routes = [
           "http://openid.aol.com/:username/",
           "http://:username.myopenid.com/",
           "http://:username.livejournal.com/",
           "http://flickr.com/photos/:username/",
           "http://technorati.com/people/technorati/:username/",
           "http://:username.wordpress.com/",
           "http://:username.blogspot.com/",
           "http://:username.pip.verisignlabs.com/",
           "http://:username.myvidoop.com/",
           "http://:username.pip.verisignlabs.com/",
           "http://claimid.com/:username/"
        ].map {|x| Router.new x}
    end

    #given a URL find out which route does it fit
    def route(url)
        for r in routes
            res = r.match url
            if res then return res
         end
    end

r = OpenIDRoutes.new
puts r.route("http://claimid.com/myusername")

Я думаю, что это хорошая и простая реализация большинства маршрутов рельсов.

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