Newsgroup: it.comp.lang.perl
Titolo: Ricerca ultima occorrenza e altre cosette

Salve a tutti,
ho un file di testo di qualche decina di migliaia di linee, fatto
cosi':
1. mille righe che non mi interessano
2. mille righe del tipo:
...
V { "tms"=0; "tck"=P; "tdi"=1; }   //
tap_tcg_select_tdr                     <= tap_testmode_ctrl_chn(15);
V { "tms"=0; "tck"=P; "tdi"=0; }   //
tap_tcg_reset_tdr                      <= tap_testmode_ctrl_chn(14);
V { "tms"=0; "tck"=P; "tdi"=1; }   //
tap_atspeed_atpg_tdr                   <= tap_testmode_ctrl_chn(13);
V { "tms"=0; "tck"=P; "tdi"=1; }   //
tap_tcg_clk_observe_tdr                <= tap_testmode_ctrl_chn(12);
V { "tms"=0; "tck"=P; "tdi"=1; }   //
tap_ext_ctrl_chn_bypass_n_tdr          <= tap_testmode_ctrl_chn(11);
V { "tms"=0; "tck"=P; "tdi"=0; }   //
tap_ram_test_thru_tdr                  <= tap_testmode_ctrl_chn(10);
...
3. mille righe che non mi interessano
Devo trovare l'ultima occorrenza della parola
"tap_tcg_clk_observe_tdr" nel file, e quel punto recuperare i valori
degli N elementi "tdi" sopra e sotto quella riga, per estrarne i
valori (cioe', nell'esempio sopra, vorrei ottenere alla fine la
stringa "101110", i valori di "tdi" intorno alla riga di interesse,
per poi fare pattern matching contro un altro file).
Quel puo' essere un strategia semplice per farlo?
Thx,
Pleg

Quel puo' essere un strategia semplice per farlo?
Ma che cosa individua il nuovo gruppo di righe di interesse? quand'� che
puoi dire che un gruppo � finito e inizia (o pu� eventualmente iniziare) il
secondo? il numero N di elementi "tdi" � noto (o comunque calcolabile) o
arbitrario?
Perch�, secondo una possibile interpretazione di quello che hai scritto,
potresti accumulare in due array ("sopra" e "sotto") i valori dei "tdi" man
mano che li incontri; quando incontri una riga "tap_tcg_clk_observe_tdr",
il "sotto" (se c'�) diventa "sopra", il "sopra" precedente (se c'�) viene
svuotato e cominci a raccogliere il nuovo "sotto"; e cos� via.
Se le cose stessero cos�, in questo modo, al peggio, dopo aver letto tutto
il file una sola volta (cio� un O(N), che � gi� un ottimo risultato) hai
tutti i valori che ti interessano.
Capisco per� che probabilmente non � quello che intendevi e i gruppi si
dividono in qualche altro modo, che per� non specifichi.
Se riesci a definire una condizione che segna l'inizio (o la fine) del
gruppo di righe di interesse, puoi costruire una macchina a due stati che:
1) accumula i risultati; 2) resta in attesa dell'eventuale nuovo gruppo di
righe.
Un'ulteriore strategia potrebbe essere leggere il file dal fondo, ci sono
anche moduli che ti aiuterebbero in questo; anche cos�, per�, devi poter
dire dove finisce l'ultimo gruppo e inizia il penultimo.
Ciao.

 Quel puo' essere un strategia semplice per farlo?
scanner.pl
 :
---
#!perl
use strict;
use warnings;
use constant {
     RIGHE_SOPRA => 8,
     RIGHE_SOTTO => 3,
     RIGHE_INIZIALI_DA_SALTARE => 0 # 1000?
};
my $input_fh = \*ARGV;
my $line_num;
while ( <> ) {
     next if $. <= RIGHE_INIZIALI_DA_SALTARE; # Ottimizzazione.
     $line_num = $. if /tap_tcg_clk_observe_tdr/
}
my @matches;
open $input_fh;
while ( <$input_fh> ) {
     next if $. < $line_num - RIGHE_SOPRA;
     push @matches, /"tdi"=(\d+);/;
     last if $. == $line_num + RIGHE_SOTTO
}
print "@matches";
---
Si esegue con:
perl 
scanner.pl
 datafile.txt
Sarebbe ulteriormente ottimizzabile sul piano velocistico, ma per file 
di qualche migliaia di righe, va bene cos�.
Ciao.

 Pleg wrote:
Scusa, mi sono dimenticato di resettare $.
Questa � la versione corretta:
---
#!perl
use strict;
use warnings;
use constant {
     RIGHE_SOPRA => 8,
     RIGHE_SOTTO => 3,
     RIGHE_INIZIALI_DA_SALTARE => 0 # 1000?
};
my $input_fh = \*ARGV;
my $line_num;
while ( <> ) {
     next if $. <= RIGHE_INIZIALI_DA_SALTARE; # Ottimizzazione.
     $line_num = $. if /tap_tcg_clk_observe_tdr/
}
my @matches;
open $input_fh;
$. = 0; # Prima mancava!


... E, sfruttando le magie dell'operatore .. (range), si pu� scrivere in 
maniera ancora pi� compatta (ed anche efficiente):
#!perl
use strict;
use warnings;
use constant {
     RIGHE_SOPRA => 8,
     RIGHE_SOTTO => 3,
     RIGHE_INIZIALI_DA_SALTARE => 0 # 1000?
};
my $input_fh = \*ARGV;
my $line_num;
while ( <> ) {
     next if $. <= RIGHE_INIZIALI_DA_SALTARE; # Ottimizzazione.
     $line_num = $. if /tap_tcg_clk_observe_tdr/
}
my @matches;
open $input_fh;
$. = 0;
while ( <$input_fh> ) {
     push( @matches, /"tdi"=(\d+);/ )
         if $. == $line_num - RIGHE_SOPRA + 1 .. $. == $line_num + 
RIGHE_SOTTO
}
print "@matches";

         if $. == $line_num - RIGHE_SOPRA + 1 .. $. == $line_num + 
il +1 non serve. Diventa quindi:
push @matches, /"tdi"=(\d+);/
    if $. == $line_num - RIGHE_SOPRA .. $. == $line_num + RIGHE_SOTTO

Fantastico, grazie!!
Pleg