2017-04-15 1 views
1

Comment les doublons de cette sortie de code peuvent-ils être arrêtés?Les sorties de boucle Ruby sont dupliquées

RE = /<("[^"]*"|'[^']*'|[^'">])*>/ 
TAG_RE = /<(.+?)>(.*?)<.+?>/ 

text = "<date>show</date> me the current conditions for <city> detroit <END>" 
a = [] 

text.scan(TAG_RE).map { |w| a<< w; } 

text.gsub(RE, '').split.each do |q| 
    a.each_with_index do |v, i| 
     if q == a[i].last.strip 
      puts "#{q}\tB-#{a[i].first}"   
     else 
      puts "#{q}\tO"   
     end 

    end 
end 

OUTPUTS

show B-date 
show O 
me O 
me O 
the O 
the O 
current O 
current O 
conditions O 
conditions O 
for O 
for O 
detroit O 
detroit B-city 

Je veux juste des cas simples du mot si elles correspondent à la condition

Vous aimez cette

show B-date 
me O 
the O 
current O 
conditions O 
for O 
detroit B-city 

Où puis-je mettre le next dans la boucle?

EDIT
Est-ce le code Rubyiotic?

text.gsub(RE, '').split.each do |q| 
    a.each_with_index do |v, i| 
     @a = a[i].last.strip # save in a variable  
     if @a == q 
      puts "#{q}\tB-#{a[i].first}"  
      break # break inner loop if match found 
     end 
    end 
    next if @a == q #skip current outer loop if match found 
    puts "#{q}\tO" 
end 
+0

Est-ce que detroit doit avoir une balise fermante ''? –

+0

Cela ne compte pas. Il suffit de vérifier les mots inclus dans les balises, puis obtient le nom de l'étiquette de la partie initiale. – arjun

Répondre

2

Le problème est que vous aussi itérez votre a qui est en fait un hachage entre les balises et les mots.

Si vous traitez votre scan par un hash au lieu d'un array, vous n'obtenez pas de doublons.

RE = /<("[^"]*"|'[^']*'|[^'">])*>/ 
TAG_RE = /<(.+?)>(.*?)<.+?>/ 

text = "<date>show</date> me the current conditions for <city> detroit <END>" 

a = text.scan(TAG_RE) 

text.gsub(RE, '').split.each do |q| 
    d = a.find { |p| p.last.strip == q } 
    if d 
    puts "#{q}\tB-#{d.first}" 
    else 
    puts "#{q}\tO" 
    end 
end 

Sortie:

show B-date 
me  O 
the  O 
current O 
conditions  O 
for  O 
detroit B-city 

Et, pendant que nous y sommes, vous pouvez utiliser un bon hash:

RE = /<("[^"]*"|'[^']*'|[^'">])*>/ 
TAG_RE = /<(.+?)>(.*?)<.+?>/ 

text = "<date>show</date> me the current conditions for <city> detroit <END>" 

map = Hash[*text.scan(TAG_RE).flatten.map(&:strip)].invert 

text.gsub(RE, '').split.each do |q| 
    tag = map[q] 
    if tag 
    puts "#{q}\tB-#{tag}" 
    else 
    puts "#{q}\tO" 
    end 
end 

qui génère la même sortie.

EDIT: Si vous vous demandez sur un plus Ruby- esque façon, je ferais probablement quelque chose comme ceci:

class Text 
    TAGS_RE = /<("[^"]*"|'[^']*'|[^'">])*>/ 
    TAGS_WORDS_RE = /<(.+?)>\s*(.*?)\s*<.+?>/ 

    def self.strip_tags(text) 
    text.gsub(TAGS_RE, '') 
    end 

    def self.tagged_words(text) 
    matches = text.scan(TAGS_WORDS_RE) 
    Hash[*matches.flatten].invert 
    end 
end 

class Word 
    def self.display(word, tag) 
    puts "#{word}\t#{Word.tag(tag)}" 
    end 

    private 

    def self.tag(tag) 
    tag ? "B-#{tag}" : "0" 
    end 
end 

text = "<date>show</date> me the current conditions for <city> detroit <END>" 

words_tag = Text.tagged_words(text) 
Text.strip_tags(text).split.each do |word| 
    tag = words_tag[word] 
    Word.display(word, tag) 
end 

Pourquoi? Je ne suis pas très intelligent et je suis très paresseux, donc je préfère écrire des choses aussi explicites que possible. Donc, j'essaie d'éviter autant que possible les cycles.

L'écriture d'une boucle est facile, mais la lecture d'une boucle n'est pas aussi simple car vous devez garder le contexte de ce que vous lisez pendant que vous continuez à lire et à analyser le code source.

Habituellement, les cycles avec break s et next s sont encore plus difficiles à analyser, car vous devez garder une trace sur les chemins de code qui terminent brusquement le cycle.

Les cycles imbriqués sont encore plus difficiles car vous devez garder la trace de plus d'un contexte qui change à différentes vitesses. Je crois que la version proposée est plus facile à lire parce que chaque ligne peut être comprise par elle-même. Il y a très peu de contexte dont nous devons nous souvenir en passant d'une ligne à l'autre.

Les détails sont résumés dans les méthodes, donc si vous voulez juste comprendre la situation, vous pouvez regarder la partie principale du code:

words_tag = Text.tagged_words(text) 
Text.strip_tags(text).split.each do |word| 
    tag = words_tag[word] 
    Word.display(word, tag) 
end 

Et si vous voulez comprendre les détails sur la façon dont il est fait, vous regardez comment les méthodes sont mises en œuvre. Avec cette approche, les détails de mise en œuvre ne sont pas divulgués aux endroits où ils pourraient ne pas être nécessaires. Je pense que c'est une bonne pratique dans tous les langages de programmation, pas seulement dans Ruby.

+0

Heya. J'ai fait une modification à la question. J'ai utilisé 'break' et' next'. Bon rubis? _BTW, votre code a bon goût. Bien sûr, aurait dû penser à «Hash»;) – arjun

+0

Merci :). J'ai mis à jour la réponse pour répondre à votre nouvelle question. – Gaston