更清楚的方法从ruby中解析字符串中的标记

时间:2009-05-21 04:09:28

标签: ruby regex openid

我正在努力清理一些东西,寻找更好的方法来解决它。我的想法是,不是在我的规则中使用正则表达式来解析字符串,我想使用更接近路径语法的东西“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 个答案:

答案 0 :(得分: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

它与您自己的代码非常相似,只有提供商列表更清晰,可以根据需要更轻松地维护和添加新的提供程序。

答案 1 :(得分:2)

String include?index怎么样?

url.include? "myuserid" 

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

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

答案 2 :(得分: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 = '^'+@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路由的一种简单实现。

答案 3 :(得分:1)

这是一个特定的URI,但标准库有URI.split():

require 'uri'

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

可能会以某种方式使用它。

C.J。