Newsgroup: it.comp.lang.perl
Titolo: aiuto estrazione stringa!

Salve,
ho necessita' di estrarre l'informazione che si trova ad una certa linea 
del codice di una pagina HTML (allegata sotto), precisamente alla linea 
74, dove in questo caso e' scritto 1.1
Ora vi chiederei:
1-qual'e' il modo semplice per farsi stampare in una variabile il valore 
scritto alla riga 74?
2-siccome non sono sicuro che questo numero sia sempre alla riga 74, 
c'e' un modo piu' "furbo" basandosi su qualche regexp che tenga conto 
dei "vicini" alla variabile che mi interessa (che sono fissi). Ho 
provato con cose del tipo:
open (IN, 'temp.txt');
while (<IN>) {
m/class="lettura">(.*)<\/td>/;
$knots_SF=$1;
}
in cui temp.txt contiene la pagina html e class="lettura"> e </td> sono 
i vicini al valore che mi interessa. Il valore verrebbe scritto sulla 
variabile knots_SF. Il problema e' che i vicini sono su righe diverse 
(il numero e' l'unica cosa sulla sua riga) e inoltre ci sono molte altre 
occorrenze di valori tra gli stessi vicini...
Non riesco a spiegarmi meglio di cosi', ma confido in qualche guru del 
perl...
**************FILE DA CUI ESTRARRE L'INFORMAZIONE *********************
<HTML>
	<HEAD>
		<TITLE>
			Condizioni meteorologiche su FONDI S.ANASTASIA
		</TITLE>
		<link rel="STYLESHEET" type="text/css" 
href="/stylesheet/style_letture.css">	
	</HEAD>
	<BODY OnLoad="javascript:startup();">
 
		<BR>
		<TABLE width="450" border="0" cellspacing="10" cellpadding="0">
			<TR align="center">
				<TD valign="top" align="center" width="450">
					<div align="center" class="desc_ctrl" id="desc_ctrl">
					FONDI S.ANASTASIA
					</div>
					<div align="center" class="taratura" id="taratura">
					&nbsp;
					</div>
					<BR>
					<div align="center" class="agg_ctrl" id="agg_ctrl">
					Dati aggiornati alle 07:42:54 del 14/09/2006
					</div>
					<table class="normal" align="center" cellspacing="0" 
cellpadding="0" width="450" id="table1">
						<TR>
							<td  align="center" WIDTH="500" class="testata_lettura">
								Data
							</td>
							<td  align="center" WIDTH="200" class="testata_lettura">
								Intensit&agrave;<BR/>(in nodi)
							</td>
							<td  align="center" WIDTH="200" class="testata_lettura">
								Direzione
							</td>
							<td  align="center" WIDTH="200" class="testata_lettura">
								Temperatura<BR/>(in C°)
							</td>
							<td  align="center" WIDTH="200" class="testata_lettura">
								Media
							</td>
						</TR>
												<TR>
							<td  align="center" class="lettura">
								14/09/2006 7.42.00
							</td>
							<td  align="center" class="lettura">
								1.1
							</td>
							<td  align="center" class="lettura">
								NNE
								<img align="absmiddle" src="/images/direzioni/ridotte/nne.gif">
							</td>
							<td  align="center" class="lettura">
								19.5
							</td>
							<td  align="center" class="lettura">
								2.12
							</td>
						</TR>
						   												<TR>
							<td  align="center" class="lettura">
								14/09/2006 7.31.59
							</td>
							<td  align="center" class="lettura">
								2.2
							</td>
							<td  align="center" class="lettura">
								NNW
								<img align="absmiddle" src="/images/direzioni/ridotte/nnw.gif">
							</td>
							<td  align="center" class="lettura">
								19
							</td>
							<td  align="center" class="lettura">
								2.28
							</td>
						</TR>

 perl...
Allora, il fatto che le stringhe che delimitano il tuo dato si trovino 
su righe diverse non è un problema: basta leggere il file in slurp mode 
(in modo da trattarlo come un'unica stringa) e poi utilizzare il 
modificatore "s" nella regex, in modo che i newline vengano trattati 
come caratteri normali.
Invece la presenza nel file di diversi numeri del tutto indistinguibili 
può essere un problema, perché non c'è niente da fare, ti devi per forza 
inventare qualche criterio aggiuntivo (te ne suggerisco qualcuno nel 
seguito), altrimenti non c'è verso di distinguere un numero dall'altro.
Il programma che ti propongo qui sotto stampa tutti i numeri (reali) che 
trova nel file compresi tra le stringhe 'class="lettura">' e '</td>', 
per cui nel particolare caso di test che hai fornito stamperebbe:
1.1
19.5
2.12
2.2
2.28
Adesso sta a te stabilire un criterio aggiuntivo per selezionare il 
numero che ti interessa: ad esempio potrebbe essere sempre quello che 
compare per primo nella pagina, oppure il numero più piccolo, o ancora 
quello compreso in un certo intervallo: solo tu puoi saperlo ;-)
Nota infine che ho imposto che il numero appaia sempre nella forma
<cifra><virgola><cifra>
Se il criterio è troppo restrittivo (ad es. se il numero può apparire 
anche senza la virgola), cambia la regex come necessario.
Ciao, Emanuele.
-------------------------------------------------------------
use strict;
use warnings;
open (IN, 'temp.txt');
local $/; # Abilita lo slurp mode.
my $page = <IN>;
# Mette tutti i numeri trovati nell'array @knots_sf.
my @knots_sf =
     $page =~
m{class="lettura">[^0-9.]*?([0-9]+\.[0-9]+)[^0-9.]*?</td>}gs;
print join "\n", @knots_sf;
__END__

 <cifra><virgola><cifra>
<cifre><virgola><cifre>
Emanuele.
-- 
What does VISTA mean?
Viruses, Infections, Spyware, Trojan horses & Adware.

 newline vengano trattati come caratteri normali.
Altra precisazione: in questo caso non avendo usato nella regex il 
metacarattere ".", il modificatore "s" in realtà non è necessario e 
pertanto lo si può omettere (se si usasse invece il metacarattere "." 
per matchare a cavallo di 2 righe, diventerebbe necessario).


 74, dove in questo caso e' scritto 1.1 [...]
Secondo me parti con il piede sbagliato, poichè "buchi" la comoda
(si fa per dire) astrazione che ti viene fornita dal fatto che il 
documento è in formato HTML. 
A te non interessa la riga 74 del file (che come hai detto, puo`
anche non essere la riga 74): mi pare piuttosto che ti interessi
il valore della colonna "Intensità" (la seconda) nella tabella 
che ha id "table1". Questi riferimenti, direi, hanno molta meno 
probabilità di variare nel tempo. 
Alternativamente, puoi identificare il dato che ti serve come
"quello che sta nella seconda casella della seconda riga della
tabella `table1`".
Detto questo, ti suggerisco un paio di moduli CPAN che possono
risolvere il problema:
  HTML::TableExtract
  HTML::TokeParser::Simple
ciao,
S.
-- 
Stefano Rodighiero      |  
http://larsen.perlmonk.org
mailto:
lar...@perl.it
   |  Italian Perl Mongers: 
http://www.perl.it

grazie davvero, sei un vero guru del perl!!
Ora sono (anzi sei) vicinissimo alla soluzione, ti spiego un attimo 
meglio cosa debbo fare:
in pratica in questa tabella html sono riportati i valori meteo di 
intensita' istantanea, direzione, temperatura e intensia' media. Dunque 
4 campi, rilevati ad intervalli regolari di tempo. A me serve intensita' 
istantanea e direzione del rilevamento piu' recente (quello che compare 
per primo nella tabella).
Dunque in sostanza lo script dovrebbe scrivere in una variabile LA PRIMA 
OCCORRENZA numerica di quelle che tu hai estratto, e in una seconda 
variabile la direzione. Ora la direzione e' una stringa che puo' andare 
da 1 a 3 caratteri, tipo S (sud), SW (sudovest), NNW (Nord-NordOvest).
Dunque nel caso in esame vorrei due variabili contenenti:
1.1 NNE
A monte di tutto c'e' pero' un problema: io lancio uno script di shell 
sotto linux dentro il quale invoco il perl mediante:
#! /usr/bin/perl
ora sotto questo comando ho inserito
use strict;
use warnings;
che tu mi hai suggerito. Adesso prima ancora di usare il tuo pezzo di 
codice ho provato a lanciare il mio vecchio script funzionante su altre 
pagine html e non funziona piu' da il seguente errore:
Global symbol "$knots_CB" requires explicit package name at ./wind.exe 
line 9.
Global symbol "$direction_CB" requires explicit package name at 
./wind.exe line 16.
Global symbol "$knots_RM" requires explicit package name at ./wind.exe 
line 25.
Hai idea del perche'? Forse mi mancano i package che stict e warnings?
grazie infinite,
gyru

Ho capito che vuoi dire, e' sicuramente un modo piu' furbo, il fatto e' 
che come si e' capito non ho troppa familiarita' col perl e non so cosa 
sia un modulo CPAN, ho paura che ci perderei ancora piu' tempo...
grazie infinite cmq, terro' presente questa possibilita'...
gyru


 Hai idea del perche'? Forse mi mancano i package che stict e warnings?
Succede perché il pragma 'use strict' ti obbliga a dichiarare le 
variabili lessicali (mediante l'operatore "my").
Per stavolta risolviamo rimuovendo use strict, ma negli script futuri ti 
esorto ad usarlo (e quindi a dichiarare ogni variabile lessicale con my 
prima di adoperarla), perché si tratta di una misura molto importante 
per la correttezza del codice Perl.
Ciao, Emanuele.
---------------------------------------------------------------
use strict;
use warnings;
open (IN, 'temp.txt');
local $/; # Abilita lo slurp mode.
# La pagina HTML deve essere *completa* (fino al tag </html>).
my $page = <IN>;
use HTML::TableExtract;
# Selezioniamo la tabella in base alle intestazioni (parziali).
my $table = HTML::TableExtract->new(
     headers => [ qw(Intensit Direzione) ]
);
$table->parse($page);
# Estraiamo la prima riga dalla tabella trovata.
my @row = @{ ($table->rows)[0] };
# Togliamo i caratteri inutili dal contenuto delle celle.
$row[0] =~ s/[^0-9.]//g;
$row[1] =~ s/[^NWOE]//g;
print "$row[0]\n"; # Stampa 1.1
print "$row[1]\n"; # Stampa NNE
__END__

 $row[1] =~ s/[^NWOE]//g;
Chiedo scusa, quest'ultima riga doveva essere:
$row[1] =~ s/[^NWSE]//g;
Ciao,
Emanuele.

ok, non sembra difficile installare il modulo, vedo di procurarmi i 
privilegi di root, la macchina che uso per girare lo script non e' sotto 
il mio controllo diretto...
Grazie infinite, ti faccio sapere non appena funzionera' tutto!!
gyru