2010-05-07 6 views
0

J'ai une chaîne comme « {certains PAROLES | sont | ici} » ou « {autre | Set | de | mots} »rubis paramétrés expression régulière

Donc, en général, la chaîne est constituée d'une ouverture accolade , mots délimités par un tuyau et un support bouclé de fermeture.

Quel est le moyen le plus efficace pour obtenir le mot sélectionné de cette chaîne?

Je voudrais faire quelque chose comme ceci:

@my_string = "{this|is|a|test|case}" 
@my_string.get_column(0) # => "this" 
@my_string.get_column(2) # => "is" 
@my_string.get_column(4) # => "case" 

Que doit la méthode get_column contenir?

+2

entretoises en bande, fendues sur le tuyau. Et vous voulez probablement dire 'get_column (2)' => ''a'' – SilentGhost

Répondre

2

C'est donc la solution que j'aime en ce moment:

class String 
    def get_column(n) 
    self =~ /\A\{(?:\w*\|){#{n}}(\w*)(?:\|\w*)*\}\Z/ && $1 
    end 
end 

Nous utilisons une expression régulière pour vous assurer que la chaîne est le format correct, tout en saisissant simultanément la bonne colonne.

Explication des expressions rationnelles:

  • \A est le beginnning de la chaîne et \Z est la fin, donc ce regex correspond à la chaîne enitre.
  • Puisque les accolades ont une signification particulière, nous leur échapper comme \{ et \} pour faire correspondre les accolades au début et à la fin de la chaîne.
  • Ensuite, nous voulons ignorer les n premières colonnes - nous ne nous soucions pas d'eux.
    • Une colonne précédente est un certain nombre de lettres suivies d'une barre verticale, nous utilisons donc l'\w standard pour correspondre à un caractère de mot semblable (y compris le nombre des underscores, mais pourquoi pas) et * pour correspondre à un certain nombre d'entre eux . La barre verticale a une signification spéciale, donc nous devons y échapper comme \|. Puisque nous voulons grouper ceci, nous l'enfermons tous à l'intérieur des parens non-capturantes (?:\w*\|) (le ?: le rend non-capturant).
    • Maintenant nous avons n des colonnes précédentes, donc nous disons à la regex de correspondre au modèle de colonne n fois en utilisant l'expression regex - il suffit de mettre un nombre entre accolades après un motif. Nous utilisons Substition de chaîne standard, de sorte que nous venons de mettre en {#{n}} signifie « correspondre au modèle précédent exactement n fois.
  • la première colonne non sauté après est celui que nous préoccupons, nous avons donc mis que la capture parens : (\w*)
  • nous sauter le reste des colonnes, le cas échéant existe:. (?:\|\w*)*

Capturer la colonne, il met en $1, ce qui nous ramène cette valeur si la regex correspondait dans le cas contraire, nous revenons nulle. , puisque cette chaîne n'a pas n e colonne.

En général, si vous voulez avoir plus que des mots dans vos colonnes (comme "{a phrase or two|don't forget about punctuation!|maybe some longer strings that have\na newline or two?}"), puis il suffit de remplacer tous les \w dans le regex avec [^|{}] de sorte que vous pouvez avoir chaque colonne contient tout sauf une frisée croisillon ou barre verticale.


Voici ma solution précédente

class String 
    def get_column(n) 
    raise "not a column string" unless self =~ /\A\{\w*(?:\|\w*)*\}\Z/ 
    self[1 .. -2].split('|')[n] 
    end 
end 

Nous utilisons une regex similaire pour vous assurer que la chaîne contient un ensemble de colonnes ou déclencher une erreur. Ensuite, nous dépouillons les accolades de l'avant et de l'arrière (en utilisant self[1 .. -2] pour limiter à la sous-chaîne commençant au premier caractère et se terminant à l'avant-dernier), diviser les colonnes en utilisant le caractère pipe (en utilisant .split('|') pour créer un tableau de colonnes) , puis recherchez la n'th colonne (en utilisant la recherche Array standard avec [n]). J'ai juste pensé que tant que j'utiliserais l'expression régulière pour vérifier la chaîne, je pourrais aussi bien l'utiliser pour capturer la colonne.