【问题标题】:Clearer way to parse a token out of a string in ruby从 ruby​​ 中的字符串中解析标记的更清晰方法
【发布时间】:2009-05-21 04:09:27
【问题描述】:

我正在尝试为它清理一些东西,并寻找一些更好的方法来解决它。这个想法是,我不想在我的规则中使用正则表达式来解析字符串,而是使用更接近路由语法“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

【问题讨论】:

    标签: ruby regex openid


    【解决方案1】:

    我认为最好的办法是生成正则表达式,正如 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
    

    它与您自己的代码非常相似,只是提供者列表更清晰,更易于维护和根据需要添加新的提供者。

    【讨论】:

      【解决方案2】:

      字符串include?index 怎么样?

      url.include? "myuserid" 
      

      或者你想要一些位置的东西?如果是这样,那么您可以split URL。

      是的第三个想法:使用您的输入表单和 :username 事物,为每个这样的字符串构造和编译一个正则表达式,然后使用 Regexp#match 返回一个 MatchData。如果你保留成对的正则表达式和 :username 字段的索引,你可以直接做。

      【讨论】:

      • 在这种情况下我不能使用常规的旧包含?我输入了“claimid.com/myusername”,然后我需要输出“myusername”。问题是输入可能是“myusername.blogspot.com”之类的东西,我仍然想要输出“myusername”。基本上是找到 openid URL 的用户名部分;但是 openid URL 可以是任何东西,并且可能找不到。听起来“第三个想法”也是我在底部示例中所做的事情?它遍历所有潜在的字符串,并获取每个字符串的“用户名”部分,清除 nil 并返回第一个。
      【解决方案3】:

      它有点特定于 URI,但标准库有 URI.split():

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

      也许能以某种方式使用它。

      C.J.

      【讨论】:

        【解决方案4】:

        我仍然认为正则表达式可以成为这里的解决方案。但是,您需要编写一个代码,从类似路由的字符串中创建一个正则表达式。示例代码是:

        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")
        

        我认为这是大多数 Rails 路由的一个很好且简单的实现。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-01-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-06-26
          • 1970-01-01
          • 2023-03-05
          • 2013-10-23
          相关资源
          最近更新 更多