2009-05-21 3 views
1

J'essaie de nettoyer quelque chose pour le diable et de trouver de meilleures façons de le faire. L'idée est qu'au lieu d'utiliser des expressions régulières dans mes règles pour analyser une chaîne, j'aimerais utiliser quelque chose de plus proche de la syntaxe des routes "something /: searchitem/somethingelse", puis une chaîne comme "/ something/FOUNDIT/somethingelse "vous obtiendriez le résultat" FOUNDIT ".Une façon plus claire d'analyser un jeton d'une chaîne en ruby ​​

Voici l'exemple que je suis refactorisation: Compte tenu d'une chaîne d'entrée, dire « http://claimid.com/myusername ». Je veux être en mesure d'exécuter cette chaîne contre un certain nombre de correspondances possibles, puis retourner le "myusername" un pour celui qui correspond.

Les données pour exécuter contre pourrait ressembler à ceci:

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" 

Toute bonne façon de faire correspondre une chaîne comme http://claimid.com/myusername à cette liste et donner un sens des résultats? Ou des techniques pour rendre quelque chose comme ça plus facile? Je regardais à travers le code de routage des rails comme il le fait quelque chose comme ça, mais ce n'est pas le code le plus facile à suivre.


En ce moment je fais juste cela avec des expressions régulières, mais il semble que la méthode ci-dessus serait beaucoup plus facile à lire

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 

Répondre

4

Je pense que votre meilleur pari est de générer les expressions régulières, comme Elazar l'a suggéré précédemment. Si vous correspondant à un seul champ (: nom d'utilisateur), alors quelque chose comme ça fonctionnerait:

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 

Il est très proche de votre propre code, seule la liste des fournisseurs est beaucoup plus propre, ce qui rend plus facile à maintenir et à ajouter nouveaux fournisseurs, au besoin.

+0

Génial, fonctionne très bien! Lot moins de code et plus facile à lire. – AdamFortuna

2

Que diriez-vous à cordes include? ou index?

url.include? "myuserid" 

Ou voulez-vous quelque chose de positionnel? Si oui, alors vous pouvez split l'URL. Oui, une troisième pensée: En utilisant votre formulaire d'entrée avec la chose: nom d'utilisateur, construisez et compilez une expression rationnelle pour chacune de ces chaînes, et utilisez Regexp#match pour renvoyer un MatchData. Si vous avez conservé des paires de Regexp et l'index du champ: nom d'utilisateur, vous pouvez le faire directement.

+0

Dans ce cas, je ne peux pas utiliser l'ancien habituel? J'ai entré "http://claimid.com/myusername" et de là j'ai besoin de sortie "myusername". Le problème est que l'entrée pourrait être quelque chose d'autre comme "http://myusername.blogspot.com" et je voudrais quand même sortir "myusername". Fondamentalement, trouver la partie du nom d'utilisateur d'une URL OpenID; mais l'URL d'ouverture peut être n'importe quoi, et pourrait ne pas être trouvé. Il me semble que la "troisième pensée" est déjà ce que je fais dans l'exemple du bas? Il parcourt toutes les chaînes potentielles et récupère la partie "nom d'utilisateur" de chacune, effaçant nils et renvoyant la première. – AdamFortuna

1

Je pense toujours que l'expression régulière peut être une solution ici. Cependant, vous devez écrire un code qui créerait une expression rationnelle hors de la chaîne de routage. Un exemple de code est:

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

Utilisez un routeur pour chaque chaîne de routage. Il devrait renvoyer une table de hachage sympa qui apparie les URL côlon-chaînes aux composants URL réels. Pour reconnaître l'URL donnée, il faut passer par tous les routeurs et trouver celui qui accepte l'URL donnée. Je pense que c'est une implémentation agréable et facile de la plupart des routages de rails.

1

C'est un peu spécifique à l'URI, mais la bibliothèque standard a un URI.split():

require 'uri' 

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

Peut-être en mesure d'utiliser cela en quelque sorte.

C.J.

Questions connexes