2013-07-03 3 views
1

Existe-t-il un moyen de faire la structure Perl suivante dans Ruby?Ruby: gamme de correspondance ligne par ligne

while(my $line = $file->each_line()) { 
    if($line =~ /first_line/ .. /end_line_I_care_about/) { 
    do_something; 
    # this will do something on a line per line basis on the range of the match 
    } 
} 

En rubis qui se lirait comme suit:

file.each_line do |line| 
    if line.match(/first_line/) .. line.match(/end_line_I_care_about/) 
    do_something; 
    # this will only do it based on the first match not the range. 
    end 
end 

La lecture du fichier en mémoire n'est pas une option et je ne sais pas quelle est la partie de la plage.

EDIT:

Merci pour les réponses, les réponses que j'ai eu où fondamentalement les mêmes que le code que j'avais en premier lieu. Le problème que j'avais était "Il peut tester l'opérande droit et devenir faux sur la même évaluation, il est devenu vrai (comme dans awk), mais il revient toujours vrai une fois."

"Si vous ne voulez pas tester l'opérande droit jusqu'à la prochaine évaluation, comme dans sed, il suffit d'utiliser trois points (" ... ") au lieu de deux. "se comporte comme" .. "fait."

Je marque la bonne réponse comme celle qui m'a montré que '..' peut être désactivé dans le même appel que celui-ci.

Pour référence, le code que je utilise est:

file.each_line do |line| 
    if line.match(/first_line/) ... line.match(/end_line_I_care_about/) 
    do_something; 
    end 
end 

Répondre

1

Je ne suis pas tout à fait clair sur la sémantique exacte du code Perl, vous supposant que vous voulez exactement la même chose. Ruby a quelque chose qui ressemble et qui fonctionne de la même façon, ou peut-être de la même manière: une plage comme une condition fonctionne comme une bascule. Le code que vous avez présenté fonctionne exactement comme je l'imagine.

Il y a quelques mises en garde, cependant:

  1. Même après avoir atteint la condition de fin, les lignes gardera en cours de lecture jusqu'à la fin du fichier. Cela peut être une considération de performance si vous vous attendez à ce que la condition de fin soit proche du début d'un fichier volumineux. La condition de démarrage peut être déclenchée plusieurs fois, en retournant le "commutateur", en faisant do_something et en testant à nouveau la condition finale. Cela peut être bien si votre condition est assez spécifique, ou si vous voulez ce comportement, mais c'est quelque chose à savoir. La condition de fin peut être appelée en même temps que la condition de démarrage est appelée, ce qui vous donne true pour une seule ligne.

est ici une alternative:

started = false 

file.each_line do |line| 
    started = true if line =~ /first_line_condition/ 
    next unless started 
    do_something() 
    break if line =~ /last_line_condition/ 
end 

Ce code lit chaque ligne du fichier jusqu'à ce que la condition de démarrage est atteinte. Ensuite, il fait le traitement que vous voulez en commençant par cette ligne jusqu'à ce que vous atteigniez une ligne qui correspond à votre condition de fin, à quel point il sort de la boucle, ne lisant plus de lignes à partir du fichier.

0

Cette solution est le plus proche de vos besoins. Il ressemble presque à Perl, mais ce Ruby valide (bien que l'opérateur de flip-flop soit un peu découragé). Le fichier est lu ligne par ligne, il n'est pas entièrement chargé en mémoire.

File.open("my_file.txt", "r").each_line do |line| 
    if (line =~ /first_line/) .. (line =~ /end_line_I_care_about/) 
    do_something 
    end 
end 

Les parenthèses sont facultatives, mais elles améliorent la lisibilité.

+0

Pouvez-vous commenter le fait que l'opérateur de bascule soit déconseillé? Je trouve cela très concis et utile et je ne vois pas pourquoi vous ne l'utiliseriez pas à moins que votre argument soit que les nouveaux programmeurs ne le sachent pas, mais là encore les nouveaux programmeurs n'en savent pas beaucoup ... – DavidG

3

Oui, Ruby supporte tongs:

str = "aaa 
ON 
bbb 
OFF 
cccc 
ON 
ddd 
OFF 
eee" 
str.each_line do |line| 
    puts line if line =~ /ON/..line =~ /OFF/ 
#puts line if line.match(/ON/)..line.match(/OFF/) #works too 
end 

Sortie:

ON 
bbb 
OFF 
ON 
ddd 
OFF