Newsgroup: it.comp.os.linux.iniziare
Titolo: sgrep, agrep, grepmail

Qualche appunto per chi è interessato all'estrazione di informazioni da
documenti strutturati, per esempio file in XML.
IN FONDO, ci sono due domande per gli esperti (antani?).
--------------------------
E' da un po' di tempo che cercavo di capire perché non mi funziona una
specifica estrazione di stringhe, mediante il tool SGREP, da un file di
testo (XHTML).
Il pattern di ricerca contiene un doppio apice e, anche da quanto scritto
nel man, per farlo digerire a sgrep, se ho capito bene, occorre (come è
facilmente arguibile) il carattere di escape prima degli apici.
Volevo cioè ottenere tutti i blocchi di testo (division) ai quali fosse
applicata una determinata classe di stile. Una cosa del genere:
---------------------------------
<div class="nomeclassestile">
jlkjlkkjhk jhkjh kjhkj hkjhk jhkj hkjh kjhkjhkjh 
k jhkjh kjhk jhkjh kjhk 
</div>
---------------------------------
All'uopo userei il comando...
sgrep '"class=\"nomeclassestile\"".."</div>"'
... ma sgrep mi restituisce sempre un "parse error", nonostante nel man si
trovi scritto quanto segue:
"
The below example query finds strings between quotation marks:
               "\"" quote "\""
"
Purtroppo, da quanto ho capito in questi giorni (in cui sulla spinta di
questo newsgroup mi sono documentato un po' di più in argomento), sgrep,
nella versione da me usata, la 1.92a, ha un baco:
http://changelogs.ubuntu.com/changelogs/pool/universe/s/sgrep/sgrep_1.94a-3/changelog
riporta:
sgrep (1.92a-4) unstable; urgency=low
  [...]
  * Fix parser to handle backslashed quotation marks in patterns. 
    (closes Bug#79495) (closes Bug#69450)
  [...]
L'ultima versione, la 1.94, non dovrebbe più contenere il baco (anche se il
changelog è meno dettagliato di quello riportato sopra e non fa riferimento
al problema:
ftp://ftp.cs.helsinki.fi/pub/Software/Local/Sgrep/sgrep-1.94a.tar.gz
 ),
tuttavia, questo "impasse" mi ha spinto a cercare altre soluzioni.
Una di queste (e che mi pare piuttosto valida) è il programma AGREP e, in
particolare "TRE agrep" (esistono due versioni di agrep: quella "storica"
di Wu-Manber e la più recente di Ville Laurikari, che è appunto
denominata "TRE agrep").
Le peculiarità di agrep sono:
- la ricerca "approssimativa",
- la possibilità di definire un delimitatore di record
- la gestione di AND e OR
Su queste feature, mi è parsa piuttosto chiara ed esauriente la seguente
risorsa web:
http://wiki.christophchamp.com/index.php/Agrep_(command)
Riguardo alla possibilità di definire un delimitatore di record, l'esempio
che viene spesso dato è quello che fa ricerche all'interno di file in
formato mbox:
agrep -d '^From ' 'pizza' nome_file_mbox
... estrae tutte le email che contengono la stringa "pizza" (ciascun
messaggio di posta in formato mbox inizia con la stringa "From" seguita da
uno spazio)
==> E qui noto subito una sovrapposizione con GREPMAIL, programma che uso
non di rado e che trovo piuttosto utile per fare ricerche su grosse moli di
posta distribuite in diversi file in formato mbox.
Grepmail è più completo, perché, essendo specificamente orientato alla
posta, "conosce" la struttura tipica di un messaggio e quindi permette di
fare filtraggi specifici solo all'interno dell'header, o solo all'interno
del body (corpo del messaggio), in base alla data, eccetera.
Riguardo alla possibilità di agrep di usare operatori logici, c'è da dire
che non siamo alla raffinatezza delle extended regular expression.
Inoltre, sgrep ha dalla sua la possibilità di utilizzare operatori logici e
un controllo dell'output superiore. Eccone un esempio nella soluzione che
ho adottato per il mio problema (opera su diversi file):
 
sgrep -o '%f   #%n\n-----------------------------
START ----------------------------\n\n %r \n\n---------------------------
END ------------------------\n\n\n' '"<div class=".."</div>"
containing "nomeclassestile"' nomefile*.htm
Ma è una soluzione che non mi soddisfa perché, quando la div che vorrei
estrarre si trova all'interno di un altra div...
      ----------------------------
      <div class="pincopallo>
      lkjlkj ljlkj lkjl kjlkj lkj lkj
      <div class="nomeclassestile">
      aaaa bbbb cccc eeee ffff hgfhgfhgfhgf hgfhgfhgf
      </div>
      </div
      -----------------------------
... il pattern estrae, ovviamente, il blocco più esteso di quello che
vorrei.
Mi pare di aver detto tutto quello che sono riuscito a capire da un esame
superficiale.
==> Ed ora un paio domande per gli esperti.
1) Mi pare che grep, egrep, agrep, sgrep, grepmail siano tutti programmi
piuttosto vecchiotti, sgrep si è fermato a una fase di testing e mi sembra
che il suo sviluppo non sia attivo, per cui mi chiedo se per svolgere
estrazioni di informazioni all'interno di file strutturati (a maggior
ragione oggi che vanno alla grande XML, XHTML, ecc.) esistano programmi
più --diciamo così-- attuali.
2) Se usate sgrep, risulta anche a voi l'anomalia dei doppi apici sopra
citata?
Non mi viene in mente nessun workaround (per sostituire nel pattern il
doppio apice non digerito), visto che sgrep non consente di usare le regexp
[*]
Grazie
[*]
      class=.\{0,1\}nomeclassestile.\{0,1\}
o (con le extended regexp)
      class=.\?nomeclassestile.\?
restituiscono il messaggio di errore "Unknown backslash escape".

 più --diciamo così-- attuali.
Come programmi stand-alone non saprei, ma se ti puo' interessare esiste una
buona libreria per python che si chiama Beautiful Soup, che fa esattamente
cio' che chiedi :
http://www.crummy.com/software/BeautifulSoup/
dai un'occhiata agli esempi, com poche linee di codice puoi
trovare/modificare cio' che vuoi in files strutturati (XML e HTML)
-- 
Ciao.
Alessandro 
"Ubuntu" - an African word, meaning "Slackware is too hard for me".

 trovare/modificare cio' che vuoi in files strutturati (XML e HTML)
Grazie, ho dato una letta veloce e mi riservo di guardare la documentazione
con più calma.
In effetti, a me servirebbe più un programma stand-alone che una libreria.
Comunque, vediamo (non conosco per niente Python)... per fare quello che,
per esempio, servirebbe a me --e cioè estrarre tutte le division di una
determinata classe di stile "xyz", dovrei scrivere in un file quanto segue?
------------------------------
#! /usr/bin/python
from BeautifulSoup import BeautifulSoup
html = open(qui_nome_del_file)
soup.find("div", { "class" : "xyz" })
-------------------------------

 -------------------------------
io me le faccio a mano tramite regexp:
questa funzione restituisce tutte le occorrenze di un determinato tag, in
un vettore
def parse_array(string, open_tag, close_tag):
	a= re.findall("(%s(.*?)%s)(?sui)" % (open_tag,close_tag), string) ret=[]
	for i in range(0,len(a)):
		ret.append(a[i][0])
	return ret	
quindi ti basta richiamarla cosě:
arr = parse_array(string, <div, </div>)

>> for tag in mytags :
...   print tag
...   print tag.renderContents()
...
<a href="
http://moca.olografix.org/home.php
" class="external text"
title="
http://moca.olografix.org/home.php
" rel="nofollow">Metro Olografix
CAmp</a>
Metro Olografix CAmp
<a href="
http://www.liberasw.org/
" class="external text"
title="
http://www.liberasw.org/
" rel="nofollow">LiberaSW: il computer è mio
e lo gestisco io</a>
LiberaSW: il computer è mio e lo gestisco io
<a href="
http://lists.linux.it/listinfo/
" class="external text"
title="
http://lists.linux.it/listinfo/
" rel="nofollow">Liste</a>
Liste
Una volta raggiunto il tuo scopo, ti sara' semplice creare il relativo
script.


 più --diciamo così-- attuali.
Perl, ad esempio, fa di tutto e di piu'. Ci sono tantissimi moduli per
lavorare con praticamente ogni tipo di informazione strutturata (cerca su
CPAN).
Inoltre, xgawk funziona molto bene per fare parsing di xml (ma e' basato su
awk, quindi bisogna conoscere awk per usarlo).
Per qualcosa di piu' nuovo di grep, guarda questo: 
http://petdance.com/ack
(che, guardacaso, e' scritto in Perl).

Ho capito abbastanza: i tuoi casi esemplificativi erano ben congegnati. Lo
terrò presente.
Thanks!

 Per qualcosa di piu' nuovo di grep, guarda questo: 
http://petdance.com/ack
Ho visto e mi è piaciuto.
La morale di tutto questo, però, è che, per file scritti con un linguaggio
di markup in cui possano esserci strutture annidate l'una nell'altra e che
abbiano il medesimo tag di chiusura, serve un parser specializzato che sia
in grado ci "contare" in modo da costruire (almeno ai fini del proprio
funzionamento) una rappresentazione ad albero della struttura.
Alla fine, fra...
- sgrep (baco o non baco);
- agrep (che è record oriented rather than just line oriented, ma
cionondimeno non prevede che un record possa trovardi all'interno di un
altro, cioè è indicato per file strutturati, ma non per file che siano
semplicemente scritti con un linguaggio di markup: quindi è OK per XML, ma
non per XHTML);
- Beautiful Soup
- perl
- hack
... per il mio problema di estrazione da un file XHTML "vincerebbe"
Beautiful Soup, con beneficio di inventario delle librerie di perl che
fossero ad-hoc per file strutturati (perché immagino che ve ne siano in
grado di comprendere (X)HTML, quindi anche a quale tag di apertura di
riferisca un tag di chiusura); mentre xgawk suppongo che vada bene per XML
ma non per (X)HTML.
Se sbaglio, DITEMELO !

 ma non per (X)HTML.
No, va bene anche per xhtml, modulo le condizioni di cui sopra.

 <div class="xyz">jhgjhgjhgjhgjhgaaa<div>bbb aaabbb aaabbb</div>
Sì, hai ragione: scusa (scusate).
La versione corretta è:
------
      dato il seguente codice:
      <div class="xyz">jhgjhgjhgjhgjhgaaa<div>bbb aaabbb aaabbb</div>kjhkjh
kjhkjhkjhkjh kj h</div>
      come fa a capire che deve estrarre...
      <div class="xyz">jhgjhgjhgjhgjhgaaa<div>bbb aaabbb aaabbb</div>kjhkjh
kjhkjhkjhkjh kj h</div>
      ... e non ...
      <div class="xyz">jhgjhgjhgjhgjhgaaa<div>bbb aaabbb aaabbb</div>
      ?
------
Quindi, mi hai già risposto. Perfetto: per strutture nidificate occorre un
parser specializzato.
Però, io distinguevo. Cioè, a mio parere, una cosa sono le strutture
nidificate in XML...
==> (e ne deducevo una conseguenza riguardo alla possibilità di estrarne
elementi compresi fra tag congruenti mediante tool non specializzati),
... altra cosa quelle nidificate in HTML (o in altro linguaggio con
parentesi bilanciate).
Perché dico questo?
Perché nel caso dell'XML la congruenza di un tag di chiusura con il tag di
apertura è evidente già dal nome del tag, ma soprattutto...
==> (correggimi se sbaglio)
perché ***non*** sono ammesse strutture di questo tipo:
<div tipo="primo">
kjhk jhkjh kjhkjh kj
kjhk jhkjh kjhk j
      <div tipo="secondo">
      aaa aaa aaaaaaaaaa aaaaaa
      aaaaaaaa  aaaaaaaaa
      </div>
kjhkjhkjh kjh kjhkj hkjh kjh
kjhkjh kjhkjhkjh kjh
</div>
... che sono invece normalissime in XHTML.
In XML posso avere solo strutture di questo tipo:
<capitolo>
kjhk jhkjh kjhkj hkjh kjhkj
kjh kjhk jhkjhk jh
      <paragrafo>
      aaa  aaaaa a  a aaaaaaa
      aaaaaaaaaaaaa aaaaaaaaaaa
      </paragrafo>
kjh kjhkj kjhk jhkjh k
kjhk jhkjh kjhkjh 
</capitolo>
oppure così:
<div tipo="primo">
kjhk jkj kjhk jhkjhkjh kjh
hjhkjhk jhkjhkjh kjh k
</div>
<div tipo="secondo">
aaaa aaaaaaaaaaaaa  aaaaaaa
aaaaaaaaaaa  aaaaaaaaaaaa a
</div>
Cioè, in sostanza: in XML, elementi identificati con tag che abbiano lo
stesso nome, anche se attributo differente, NON è ammesso che siano
annidati l'uno nell'altro (l'elemento figlio deve essere identificato con
un nome diverso dal padre e non semplicemente con un attributo diverso),
mentre in XHTML questo è possibile.
==> Se questa premessa è corretta (ma vedi subito qui oltre), io ne deduco
che per l'XML possono essere utilizzati anche parser ***non***
specializzati.
Se invece questa premessa è sbagliata, allora: OK siamo d'accordo che
occorre comunque un parser specializzato.
==> Azzarderei l'ipotesi (tentando di rispondermi da solo) che, in realtà,
non esista una regola che impone di identificare con un tag diverso nel
nome un elemento figlio [1], anche se --devo dire-- dal punto di vista
sostanziale ciò mi pare poco sensato (io finora non ho mai trovato
strutture del genere [2]).
[1]
<padre>
      <figlio>
      </figlio>
      <figlio>
      <fglio>
</padre
[2]
<elemento classe="padre">
      <elemento classe="figlio">
      </elemento>
      <elemento classe="figlio">
      </elemento>
</elemento>

 occorre comunque un parser specializzato.
Non e' strettamente obbligatorio; diciamo che e' obbligatorio se si vuole
rimanere sani di mente.

 
Io, pensando --detto in breve-- che in XML un elemento figlio non potesse
avere lo stesso nome del padre, avevo argomentato facendo un mix tra regole
formali e un mio assunto riguardante la semantica.
E poi, riflettendoci meglio, è anche vero che dei figli annidati l'uno
nell'altro e identificati tutti come "figlio" costituiscono una struttura
semanticamente corretta, perché, anche se di diverso livello, non si può
negare che tutti gli elementi siano --appunto-- dei figli.
DETTO CIO', tento di ricambiare (in modo forse un po' originale) con un
supplemento, riguardante sgrep (che mi hai detto che non conosci), che
forse potrebbe suggerirti qualche idea e interessare ad altri che abbiano
seguito questo thread: vedere il post successivo intitolato "sgrep".