web-dev-qa-db-fra.com

Ruby Chaîne divisée avec regex

C'est Ruby 1.8.7 mais devrait être le même que pour 1.9.x

J'essaie de diviser une chaîne par exemple:

a = "foo.bar.size.split('.').last"
# trying to split into ["foo", "bar","split('.')","last"]

Fondamentalement, en le divisant en commandes qu'il représente, j'essaie de le faire avec Regexp mais je ne sais pas comment, l'idée était d'utiliser regexp

a.split(/[a-z\(\)](\.)[a-z\(\)]/)

Ici, essayer d'utiliser le groupe (\.) pour le diviser mais cela ne semble pas être une bonne approche.

21
Haris Krajina

Je pense que cela le ferait:

a.split(/\.(?=[\w])/)

Je ne sais pas ce que vous savez sur l'expression régulière, mais le (?=[\w]) est une anticipation qui dit "ne faire correspondre le point que si le caractère suivant est un type de lettre". Une tête de lecture ne saisira pas réellement le texte auquel elle correspond. Il "regarde" simplement. Le résultat est donc exactement ce que vous recherchez:

> a.split(/\.(?=[\w])/)
 => ["foo", "bar", "size", "split('.')", "last"] 
31
Jason Swett

Je crains que les expressions régulières ne vous mènent très loin. Considérez par exemple les expressions suivantes (qui sont également des rubis valides)

"(foo.bar.size.split( '.' )).last"
"(foo.bar.size.split '.').last"
"(foo.bar.size.split '( . ) . .(). .').last"

Le problème est que la liste des appels est en fait une arborescence d'appels. La solution la plus simple en vue est probablement d'utiliser un Ruby et de transformer l'arbre d'analyse en fonction de vos besoins (dans cet exemple, nous descendons récursivement dans l'arborescence des appels, rassemblant les appels dans une liste) :

# gem install Ruby_parser
# gem install awesome_print
require 'Ruby_parser'
require 'ap'

def calls_as_list code
    tree = RubyParser.new.parse(code)

    t = tree
    calls = []

    while t
        # gather arguments if present
        args = nil
        if t[3][0] == :arglist
            args = t[3][1..-1].to_a
        end
        # append all information to our list
        calls << [t[2].to_s, args]
        # descend to next call
        t = t[1]
    end

    calls.reverse
end

p calls_as_list "foo.bar.size.split('.').last"
#=> [["foo", []], ["bar", []], ["size", []], ["split", [[:str, "."]]], ["last", []]]
p calls_as_list "puts 3, 4"
#=> [["puts", [[:lit, 3], [:lit, 4]]]]

Et pour afficher l'arbre d'analyse de toute entrée:

ap RubyParser.new.parse("puts 3, 4")
7
Matt
a = "foo.bar.size.split('.').last"
p a.split(/(?<!')\.(?!')/)

#=> ["foo", "bar", "size", "split('.')", "last"]

Vous recherchez des assertions Lookahead et Lookbehind. http://www.regular-expressions.info/lookaround.html

4
thebugfinder

ici je n'ai pas Ruby env. J'ai essayé avec python re.split ().

In : re.split("(?<!')\.(?!')",a)
Out: ['foo', 'bar', 'size', "split('.')", 'last']

l'expression rationnelle ci-dessus a un lookahead négatif ET regardez derrière, pour vous assurer que seul le "point" entre les guillemets simples ne fonctionnera pas comme séparateur .

bien sûr, pour l'exemple donné par vous, l'un de lookbehind ou lookahead est suffisant. vous pouvez choisir la bonne manière pour votre condition.

2
Kent