2009-04-22 6 views
0

Je voudrais écrire un script qui prend un argument qui pourrait ressembler à ceci:Comment puis-je analyser une chaîne contenant des caractères génériques et des classes de caractères dans Ruby?

abc(ag)de* 

a, b, c sont des caractères littéraux.

(ag) signifie «an 'a' ou 'g'».

* signifie une lettre ou un chiffre.

Je veux que le script crée un tableau de toutes les chaînes possibles que l'entrée pourrait représenter. (Le but est de vérifier s'ils sont des noms de domaine disponibles.)

L'entrée pourrait aussi être quelque chose comme abc(ag)de(mnlop) où il y a plus que sur la classe de caractères.

On dirait que la première tâche est de le diviser en un tableau ou des tableaux, de sorte que le premier exemple serait ...

[ 
    ['a'], 
    ['b'], 
    ['c'], 
    ['a', 'g'], 
    ['d'], 
    ['e'], 
    [ 
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 
    # etc... 
    ] 
] 

C'est là que je suis bloqué. Je ne sais pas comment le diviser en morceaux comme ça.

Des suggestions sur la façon de l'aborder?

+0

Il manque un mot dans le titre entre "a" et "that". Je ne suis pas sûr de ce que le mot correct serait ("chaîne"?), Donc vous devriez corriger cela;) – OregonGhost

+0

Vous pouvez trouver la réponse C# j'ai posté à http://stackoverflow.com/questions/710670/c-permutation -of-an-array-of-arraylists/710716 # 710716 utile. Dans votre cas, les tableaux seraient ceux que vous générez déjà pour votre premier stask. L'algorithme récursif de base devrait être relativement facile à traduire en une solution à votre problème. Mais je ne connais pas Ruby alors je te laisse ou quelqu'un d'autre. – Brian

Répondre

5

Voici une solution assez compacte. Il n'est en aucun cas optimisé pour les performances, ce qui impose certaines contraintes sur les modèles que vous fournissez, par ex. trop de caractères génériques n'est probablement pas la meilleure idée.

est ici le code

input1 = "abc(ag)de*" 
input2 = "abc(ag)de(mnlop)" 

class Array 
    def append_suffixes!(suffixes) 
    self.replace suffixes.map { |a| self.map { |p| p + a }}.flatten 
    end 
end 

def generate_combinations(pattern) 
    combinations = [""] 
    pattern.scan(/\(([^)]+)\)|(\*)|(\w+)/) do |group,wildcard,other| 
    new_suffixes = case 
     when group : group.split('') 
     when wildcard : [*'a'..'z'] 
     when other : other 
     else raise "Unknown match!" 
    end 
    combinations.append_suffixes! new_suffixes 
    end 
    combinations 
end 

p generate_combinations(input1) 
p generate_combinations(input2) 
p generate_combinations("**").size 

La sortie de l'exécution du code ci-dessus est (légèrement modifié):

["abcadea", "abcgdea", "abcadeb", "abcgdeb", "abcadec", 
"abcgdec", "abcaded", "abcgded", "abcadee", "abcgdee", 
"abcadef", "abcgdef", "abcadeg", "abcgdeg", "abcadeh", 
"abcgdeh", "abcadei", "abcgdei", "abcadej", "abcgdej", 
"abcadek", "abcgdek", "abcadel", "abcgdel", "abcadem", 
"abcgdem", "abcaden", "abcgden", "abcadeo", "abcgdeo", 
"abcadep", "abcgdep", "abcadeq", "abcgdeq", "abcader", 
"abcgder", "abcades", "abcgdes", "abcadet", "abcgdet", 
"abcadeu", "abcgdeu", "abcadev", "abcgdev", "abcadew", 
"abcgdew", "abcadex", "abcgdex", "abcadey", "abcgdey", 
"abcadez", "abcgdez"] 

["abcadem", "abcgdem", "abcaden", "abcgden", "abcadel", 
"abcgdel", "abcadeo", "abcgdeo", "abcadep", "abcgdep"] 

676 # The number of two letter words i.e. 26*26 

S'il vous plaît ne hésitez pas à demander si vous avez des questions sur le code ci-dessus.

1

Si votre * signifie seulement un seul caractère, alors je suppose que c'est au moins résoluble. Si cela signifie "zéro ou plus de n'importe quel caractère", alors vous avez l'impression que votre espace de solution est proche de l'infini, et sera donc difficile à retourner en tant que valeur concrète réelle. Je pense que j'aborderais cela en séparant d'une façon ou d'une autre les parties variables, en calculant le nombre de variantes supportées, puis en bouclant (conceptuellement) toutes les variables d'une manière imbriquée, formant une chaîne de sortie pour chaque itération boucle.

Pour l'exemple chaîne de "abc (ag) de *", ce serait faire bouillir jusqu'à ce (pseudo-code Python-ish, mon Ruby est pas pour un usage public):

results = [] 
for x in "ag": 
    for y in "abcdefghijklmnopqrstuvwxyz": 
    results.append("abc%sde%s" % (x, y)) 

Le % s dans la chaîne sur la ligne finale est un spécificateur de format, s signifie simplement "chaîne", et provoquera la valeur correspondante de tuple à la droite de l'opérateur% après la chaîne à interpoler à cette position.

+0

L'étoile signifie un seul caractère. – Ethan

1

Ce que vous demandez essentiellement, c'est de prendre une expression rationnelle et de générer toutes les chaînes correspondantes.

C'était Ruby Quiz #143. Jetez un oeil aux solutions sur le côté gauche.

Questions connexes