2009-05-21 27 views
1

我正在嘗試清理它的地獄,並尋找一些更好的方法去實現它。我的想法是,我不想在我的規則中使用正則表達式來解析字符串,而是使用更接近路由語法「something /:searchitem/somethingelse」的東西,然後給出一個字符串,如「/ something/FOUNDIT/somethingelse 「你會得到結果」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

我認爲你最好的選擇是生成正則表達式,正如Elazar先前所建議的那樣。如果你只是匹配一個字段(:用戶名),那麼像這樣的工作:

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 

它非常類似於自己的代碼,只有供應商的名單是更清潔,更易於維護和補充根據需要提供新供應商

+0

太棒了,效果很棒!很少的代碼和更容易閱讀。 – AdamFortuna 2009-05-22 02:13:47

2

如何字符串include?index

url.include? "myuserid" 

或者你想要一些位置的東西?如果是這樣,那麼你可以用split這個URL。

是的第三個想法:使用您的輸入形式與:用戶名的東西,構造和編譯每個這樣的字符串的正則表達式,並使用Regexp#match返回MatchData。如果您保留了正則表達式的對和用戶名字段的索引,則可以直接進行。

+0

在這種情況下,我不能使用普通的老包括?我輸入「http://claimid.com/myusername」,從那裏我需要輸出「myusername」。問題是輸入可能是其他類似「http://myusername.blogspot.com」,我仍然希望輸出「myusername」。基本上找到openid URL的用戶名部分;但openid網址可能是任何內容,並且可能找不到。 這聽起來像「第三個想法」是我在底部的例子中已經做了什麼?它貫穿所有可能的字符串,並獲得每個字符串的「用戶名」部分,清除nils並返回第一個字符串。 – AdamFortuna 2009-05-21 04:43:23

1

我仍然認爲正則表達式可以成爲一個解決方案。然而,你需要編寫一個代碼來創建一個類似於路由的字符串的正則表達式。示例代碼是:

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 = '^'[email protected]+'$' 
     @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") 

我認爲這是一個不錯的和易於實現的大多數軌道路由。

1

這是一個特定的URI,但標準庫有URI。split():

require 'uri' 

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

可能會以某種方式使用它。

C.J.