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