Comment puis-je marquer cette chaîne dans Ruby?
J'ai cette chaîne:
%{Children^10 Health "sanitation management"^5}
Et je veux le convertir pour marquer cela dans un tableau de hachages:
[{:keywords=>"children", :boost=>10}, {:keywords=>"health", :boost=>nil}, {:keywords=>"sanitation management", :boost=>5}]
Je suis conscient de StringScanner et la La syntaxe de gem mais je ne trouve pas assez d'exemples de code pour les deux.
Les pointeurs?
source d'informationauteur Radamanthus
Vous devez vous connecter pour publier un commentaire.
Pour une vraie langue, un analyseur lexical est la voie à suivre - comme dit Guss. Mais si le langage est seulement aussi compliqué que votre exemple, vous pouvez utiliser cette rapide hack:
Si vous êtes en essayant d'analyser un langage régulier alors cette méthode suffira - bien qu'il ne serait pas beaucoup plus de complications pour faire de la langue non-régulière.
Une rapide décomposition de la regex:
\w+
correspond à n'importe quel terme de mots clés(?:\\.|[^\\"]])*
utilise non-capture de parenthèses ((?:...)
) pour correspondre au contenu de la séquence d'échappement double chaîne de caractères entre guillemets -, soit une fuite de symbole (\n
\"
\\
etc.) ou un seul caractère qui n'est pas une évasion symbole ou une fin de citation."((?:\\.|[^\\"]])*)"
ne prend en compte que le contenu d'un coté expression de mot-clé.(?:(\w+)|"((?:\\.|[^\\"])*)")
correspond à n'importe quel mot-clé - un seul terme ou d'une expression, la capture d'une seule des termes dans$1
et l'expression contenu dans$2
\d+
correspond à un numéro.\^(\d+)
de capture d'un nombre à la suite d'un accent circonflexe (^
). Depuis c'est le troisième jeu de la capture de parenthèses, il sera caputred en$3
.(?:\^(\d+))?
de capture d'un nombre à la suite d'un signe si il y est, correspond à la chaîne vide sinon.String#scan(regex)
correspond à l'expression rationnelle contre la corde autant de fois que possible, outputing un tableau de "matchs". Si la regex contient la capture des parens, un "match" est un tableau d'éléments capturés - donc$1
devientmatch[0]
$2
devientmatch[1]
etc. Capture parenthèse qui n'est pas en correspondance avec la partie de la chaîne correspond à unnil
entrée dans la "correspondance".La
#map
prend alors ces matchs, utilise certaines bloc magique pour casser chaque capturé terme dans des variables différentes (nous aurions pu fairedo |match| ; word,phrase,boost = *match
), puis crée votre choix hachages. Exactement l'un desword
ouphrase
seranil
car les deux ne peuvent pas être comparés à l'entrée, donc(word || phrase)
sera de retour le non -nil
et#downcase
va le convertir en minuscules.boost.to_i
permettra de convertir une chaîne en un entier, alors que(boost.nil? ? nil : boost.to_i)
permettra de s'assurer quenil
stimule séjournil
.Ici est un non-robuste exemple à l'aide de
StringScanner
. Ce code, je l'ai juste adapté à partir de Ruby Quiz: Parsing JSONqui a une excellente explication.Ce que vous avez ici est arbitraire, de la grammaire, et d'analyser ce que vous voulez vraiment est un lexer - vous pouvez écrire un fichier de grammaire qui décrit la syntaxe et ensuite utiliser l'analyseur lexical pour générer un appel récursif à l'analyseur de votre grammaire.
L'écriture d'un analyseur lexical (ou même un appel récursif à parser) n'est pas vraiment trivial - même si c'est un exercice utile de programmation, mais vous pouvez trouver une liste des Rubis lexers/analyseurs dans ce message ici: http://newsgroups.derkeiler.com/Archive/Comp/comp.lang.ruby/2005-11/msg02233.html
RACC est disponible en tant que module standard de Ruby 1.8, alors je vous suggère de se concentrer sur que même si le manuel n'est pas vraiment facile à suivre et exige de la familiarité avec yacc.