Newsgroup: it.comp.os.linux.iniziare
Titolo: Estrapolare stringhe da PDF

Ciao a Tutti,
 
devo estrapolare i cognomi i nomi e l’indirizzo da diversi documenti in 
pdf e copiarli in un foglio di calcolo.
 
Esempio:
 
      A	     B	   C	
1) cognome nome indirizzo
2) cognome nome indirizzo
3) cognome nome indirizzo
 
Poichè alcuni di questi pdf sono composti anche da 15 pagine, il mio 
intento, sarebbe quello di costruire uno script che mi re-dirige le 
stringhe da estrapolare in un file .txt, che in seguito importerò in Calc 
di LibreOffice.
 
Esempio:
--------------------------------------------
#!/bin/bash
comando > file.txt
exit
--------------------------------------------
Sfortunatamente i campi non sono adiacenti, per cui avrei bisogno 
dell’aiuto di qualcuno più esperto di me, a tale proposito, vi scrivo qui 
di seguito, il link dove potete vedere la prima pagina del pdf 
(naturalmente per questioni di privacy, tutti i riferimenti alle persone 
sono stati modificati)
 
https://drive.google.com/open?id=1FcC9M6eUqGwdbeTAHx7iM2juAOIjEIpC
 
 
Non mi sono mai cimentato in un lavoro di questo tipo, cioè di estrazione 
stringhe, per cui sono alle prime armi.
Vi ringrazio in anticipo per qualsiasi risposta positiva.
Nemo
 
 
 
 

 pdf e copiarli in un foglio di calcolo.
 
Io non ci sono riuscito ma ho visto che è possibile elaborare i file odf
e quindi io convertirei i pdf in odf e poi agirei su quelli. Poi
occorrono dei programmini già fatti che ho trovato in php.
 
-- 
Sandro kensan 
www.kensan.it
 & 
www.qiqi.it
 geek site
Saluto gli agenti della NSA - Hello NSA - 
www.nsa.gov
 

 occorrono dei programmini già fatti che ho trovato in php.
 
Ciao, grazie per la tua risposta!
Con Abiword ho trasformato il pdf in .odt (26 pagine), il quale mi ha 
sistemato ogni campo su una riga, per cui ora i campi Cognome, None ed 
Indirizzo si ripetono a capo con una certa frequenza ordinata.
 
Ho letto che con  "grep"  si possono escludere stringhe che contengono 
determinati caratteri, mentre con "sed" è possibile cancellare l'ultima 
riga di un file....
 
Dove hai trovato i programmi in php? La cosa mi interessa molto, perchè 
ora devo risolvere questo problema, ma la cosa mi può essere utile anche 
in futuro.
 
Ciao,
Nemo

 in futuro.
 
Si tratta di un certo lavoro di programmazione, un po' complesso e
secondo me fai prima a farlo a mano il lavoro. Se invece hai molte
pagine e vuoi passare una giornata a programmare in php allora ti posso
fornire alcuni suggerimenti ma dovresti essere esperto nella
programmazione perché nessuno scriverà il codice al posto tuo.
 
Per accedere al file odt devi prima capire come è strutturato, devi
sapere cosa è un file zip e cosa è un DOM. Detto questo io ho costruito
(copiando vari pezzi) la funzione php che fa questo:
 
function odt($template, $path, $change, $name_doc){
    /***************************************************
    / la funzione odt() ha come ingresso il Template.odt che viene
modificato cambiando
    / tutte le occorrenze dei suoi placeholders con i valori presenti in
change.
    / Il risultato viene salvato in name_doc.odt. I placeholder presenti
in Template.odt
    / e i tag di change sono valori legati. Viene creata una cartella
temporanea di
    / nome tmp per elaborare il documento libre office. Template.odt non
viene mai
    / modificato. $change["Titolo"] = "Affitto casa a Roma", Titolo e'
presente in Template.
    / <a href="'.$SITE_WWW.$SITE_DIRECTORY.'/'.$path.'/'.
    / $name_doc.'.odt'.'">Volantino.odt</a><
    *///////////////////////////////////////////////////
 
per capire cosa fa guarda questo articolo:
 
https://www.kensan.it/articoli/Volantino.php
 
 
A te non rimarrebbe che navigare nel DOM alla ricerca dei campi che ti
interessano e di salvarli in un file txt, dovresti quindi modificare la
mia funzione odt() in modo opportuno.


 
https://drive.google.com/open?id=1FcC9M6eUqGwdbeTAHx7iM2juAOIjEIpC
 
 
Io ho provato così:
 
pdftotext -layout Downloads/1NASCITE.pdf 1NASCITE.txt
 
Questo ti converte il pdf in un file tesuale da scandagliare
con grep per estrarre con sed ed altri strumenti i dati che
servono. L'opzione -layout mantiene per quanto possibile la
fisionomia della pagina pdf in input ecco come appare il file
testuale che salta fuori 1NASCITE.txt:
--------------------------------------
99854 ROSSI                                                MARIO                                             M
Nato a:    xxx                           il   xx/xx/2017   Atto nascita:   XXX, xxx
                                                                           xx/2017
Residenza:
             VIA ROMA n. 9 Sc. B
Cittadinanza:    ITALIANA
Pat/Mat:     xxx xxx/xxx xxx
                                                                                        Data Rif.:   xx/xx/2017
 
99887 ROSSI                                                ROMEO                                             M
Nato a:    xxx                           il   xx/xx/2017   Atto nascita:   XXX, xxx
                                                                           xx/2017
Residenza:
             VIA VENEZIA n. 9
Cittadinanza:    ITALIANA
Pat/Mat:     xxx xxx /xxx xxx
 
--------------------------------------
 
Ok per le colonne standard di usenet è un po' largo... pazienza.
Ciò che conta è osservare che:
- Il nome e cognome appartengono alle righe precedenti
  a quella che inizia col pattern "Nato a".
- L'indirizzo di residenza appartiene alla riga successiva a
  quella che inizia col pattern "Residenza".
- tutte le altre righe le possiamo buttare via.
- il COGNOME e il NOME sono separati da tanti spazi, almeno
  più di cinque spazi... Questo è importante per non avere
  problemi con eventuali nomi o cognomi costituiti da due
  o più parole:
  MARIA CRISTINA ROSSETTI
  ALBERTO MARIA DE SANCTIS
 
  Se il formato del PDF passato in testo è quello riportato
  ci aspettiamo di trovare qualcosa come:
 
  ROSSETTI                      MARIA CRISTINA
  DE SANCTIS                    ALBERTO MARIA 
 
  e possiamo sfruttare così il grande numero di spazi come separatore
  dei due campi "COGNOME" "NOME".
 
 
 
 
L'idea operativa può essere:
- estraiamo le righe contenenti "cognome nome".
- le ripuliamo dai numeri iniziali e dal "sesso" finale
- avremo una colonna di righe contenenti solo "COGNOME       NOME"
- inseriamo un separatore, ad esempio ";" al posto della sfilza di
  spazi consecutivi che separano il cognome dal nome
- questa doppia colonna COGNOME;NOME la stampiamo su un file di
  appoggio "tmp-nomi.txt".
- estraiamo le righe contenenti l'indirizzo di residenza.
- togliamo gli spazi iniziali e finali in eccesso
- e abbiamo una colonna con gli indirizzi uno per riga
- questa colonna la stampiamo su un secondo file di appoggio
  temporaneo tmp-indirizzi.txt
 
Alla fine facciamo un "paste" dei due files temporanei indicando
come separatore dei campi il punto e virgola, siccome l'abbiamo
già scelto prima come separatore dei campi COGNOME e NOME.
Abbiamo così ottenuto un file CSV di tre colonne separate da
punto e virgola importabile anche in Calc.
 
 
 
Veniamo alla pratica:
 
ho buttato giù uno script bash piuttosto semplice chiamato
parse-nascite.sh
Gli si passa come primo argomento da linea di comando il nome
del file PDF di partenza.
E lui stampa a video il file CSV finale con cognome;nome;residenza
 
--------------------------------
./parse-nascite.sh 1NASCITE.pdf
--------------------------------
ROSSI;MARIO;VIA ROMA n. 9 Sc. B
ROSSI;ROMEO;VIA VENEZIA n. 9
VERDI;FRANCO;VIA FIRENZE n. 15 int. 5
NERI;GIANNI;VIA ALPI n. 74 int. 8
NERI;RENZO;VIA APPENNINI n. 8 int. 3
GIALLI;LUCIA;VIA MARE n. 44 Sc. A
---------------------------------
 
Se si vuole redirigere il tutto su un file di testo chiamato ad esempio
nascite.txt da importare in Calc o da trattare successivamente, basta
lanciarlo così:
 
parse-nascite.sh 1NASCITE.pdf > nascite.txt
 
Ecco infine lo script:
----------
#!/bin/sh
 
INPUT=$1
CONVERTED=tmp-converted.txt
pdftotext -layout $INPUT $CONVERTED
grep -B1 'Nato a' $CONVERTED|sed /^Nato\ a/,/^--$/d|sed 's/^[0-9]*\s\(.*[A-Z]\)\s*[M,F]$/\1/'| sed 's/\s\{5,\}/;/' > tmp-nomi.txt
grep -A1 'Residenza' $CONVERTED |sed /--/d\;/Residenza/d|sed 's/^ *//' > tmp-indirizzi.txt
paste -d\; tmp-nomi.txt tmp-indirizzi.txt
rm tmp-nomi.txt tmp-indirizzi.txt $CONVERTED
--------------------------------------------
 
Il tutto sarà migliorabilissimo, però è un punto
di partenza che potrebbe già bastare per le tue
esigenze.
 
 
Saluti!  :)

.
===============================================================================
 
Mi piacerebbe usare molto usare questa soluzione, perchè con uno script 
unico estrapolo le stringhe desiderate, copiandole in un secondo file.txt
 
Il tutto da importare in Calc per il Mail-Merge.
 
Ciao e grazie in anticipo per il tuo aiuto,
Nemo
 
 

 Il tutto da importare in Calc per il Mail-Merge.
 
Mail-Merge?
 
Ah usalo pure...
E se ti serve spesso fare cose del genere guardati
qualche manuale di scripting bash... a ai tempi
aveva aiutato.
 
Buona fortuna!  :D
Ciao

 Buona fortuna!  :D Ciao
 
Sicuramente lo farò. Sapevo già che Linux aveva una marcia in più, ma ora 
con questo script ne ho la conferma.
 
*GRAZIE 1.000.000.000* per il tuo aiuto!!
 
Un cordiale saluto,
Nemo

 hanno la cittadinanza. Mi studio bene grep e sed.
 
Non ho capito bene cosa intendi per "cittadinanza al posto di
indirizzo"...
Probabilmente i due indirizzi mancanti derivano dal fatto che
quella particolare pagina ha delle caratteristiche diverse
dalle altre. Meglio di te che hai davanti il PDF effettivo
da trattare non può saperlo nessuno.


Ho capito il perchè. Per un qualche motivo, il file CONVERTED.txt ha i 2 
indirizzi sulla stessa riga della *Residenza:* e non dopo, per cui lo 
script, che fa il suo lavoro,  estrapola la riga 
grep -A(fter)1 'Residenza' $CONVERTED.
Comunque, il file pdf di 7 pagine, con 38 persone ha solamente 2 errori, 
che possono essere sistemate a mano.
 
 
Ora mi sto dedicando ad un altro PDF, chiamato Immigrati.pdf, il quale 
trasformato in Immigrati.txt, contiene lo LAYOUT del pdf.
 
Ho modificato la riga dell'indirizzo in:
 
grep -B1 'Immigrato da' $CONVERTED|sed /^Immigrato\ da/,/^--$/d|sed 's/^
[0-9]*\s\(.*[A-Z]\)\s*[M,F]$/\1/'| sed 's/\s\{5,\}/;/' | sed 's/
Residenza://' > tmp-indirizzi.txt
 
ed ho aggiunto, alla fine, la stringa:
| sed 's/Residenza://'
in questo modo mi estrapola solamente la riga Residenza: Via Garibaldi, 4 
sc.2 Int5, e mi cancella la parte iniziale della riga e cioè: Residenza:, 
lasciando solamente l'indirizzo: Via Garibaldi, 4 sc.2 Int5 !!!
 
Solamente che il mio file finale immigrati.txt è strutturato in questo 
modo:
 
;ROSSI                        MARIO; VIA ROMA,45
;ROSSI                        ROMEO; VIA GARIBALDI,37
;NERI                        FRANCO; VIA MILANO,36
;VERDI                       CINZIA; VIA TORINO,21
 
Scrivo qui di seguito lo script completo:
#!/bin/sh
 
INPUT=$1
CONVERTED=tmp-converted.txt
pdftotext -layout $INPUT $CONVERTED
grep -B1 'Nato a' $CONVERTED|sed /^Nato\ a/,/^--$/d|sed 's/^[0-9]*\s\(.*
[A-Z]\)\s*[M,F]$/\1/'| sed 's/\s\{5,\}/;/' > tmp-nomi.txt
 
grep -B1 'Immigrato da' $CONVERTED|sed /^Immigrato\ da/,/^--$/d|sed 's/^
[0-9]*\s\(.*[A-Z]\)\s*[M,F]$/\1/'| sed 's/\s\{5,\}/;/' | sed 's/
Residenza://' > tmp-indirizzi.txt
 
paste -d\; tmp-nomi.txt tmp-indirizzi.txt
rm tmp-nomi.txt tmp-indirizzi.txt $CONVERTED 
 
 
Ciao,
Nemo

 [A-Z]\)\s*[M,F]$/\1/'| sed 's/\s\{5,\}/;/' > tmp-nomi.txt
 
Il problema potrebbe dartelo anche i nomi...
Per capirlo devi spezzare il comando e aggiungere pipe e successivo
comando per tentativi sulla base dell'output precedente. Cioè prendi
il file converted.txt e guarda cosa salta fuori applicando solo una 
prima parte della serie di piepes (la pipe è la sbarretta verticale "|"),
ad esempio:
 
grep -B1 'Nato a' tmp-converted.txt
 
E guardi com'è l'output...
Quindi aggiungi una pipe:
 
grep -B1 'Nato a' $CONVERTED \
   |sed /^Nato\ a/,/^--$/d
 
e guardi cosa salta fuori...
Poi se è coerente con l'output (e devi vederlo tu, io non
ho il file di partenza...) applicherai il pezzo successivo:
 
grep -B1 'Nato a' $CONVERTED \
   |sed /^Nato\ a/,/^--$/d \
   |sed 's/^[0-9]*\s\(.*[A-Z]\)\s*[M,F]$/\1/'
 
L'inghippo potrebbe saltare fuori da questo output. Dall'er-
rore sopra riportato sembrerebbe che all'inizio delle righe
ci sia una serie di spazi (più di cinque) che vengono trasfor-
mati in ";" dal comando successivo cioè:
 
sed 's/\s\{5,\}/;/'
 
Questo spiega i "punto e virgola" a inizio riga nell'output finale
prima del nome... Invece dovrebbe essere tra il nome e cognome.
Se è questo il caso dovresti prima cancellare gli spazi iniziali
e quindi applicare la sostituzione della "serie lunga" di spazi
che separano il cognome dal nome.
 
Per farlo dovrai modificare l'ultimo sed delle pipe:
 
sed 's/^[0-9]*\s\(.*[A-Z]\)\s*[M,F]$/\1/'
 
In qualcosa di un po' diverso (devi vedere tu come è fatto
l'out e modificare di conseguenza).
Il pattern sopra dice:
 
inizio riga
stringa numerica di lunghezza arbitraria
un solo spazio
memorizza quello che viene dopo fino all'ultimo carattere alfabetico
serie di spazi ripetuta arbitraramente N volte (\s*)
carattere M oppure F
fine riga
 
A tutto ciò viene sostituito il pezzo memorizzato,
che probabilmente nel caso di questo file contiene
spazi iniziali...
Quindi potresti risolvere impostando una serie arbitraria di
spazi invece di un unico spazio prima del pezzo da memorizzare:
in pratica:
 
\s*\(.* ecc ecc
 
al posto di
 
\s\(.* ecc ecc
 
 
La mia è però solo un'ipotesi visto che, ripeto, non
avendo il file di input brancolo nel buio a tentoni.
 
 
 
Altro appunto è meglio che rimuovi gli spazi iniziali
anche dall'indirizzo in modo che venga fuori:
 
;VIA ROMA,45
 
Invece di
 
; VIA ROMA, 45
 
Questo è facile, basta aggiungere uno o più spazi al pattern
quando rimuovi "Residenza:"..
cioè
 
sed 's/Residenza:\s*//'
 
invece di
 
sed 's/Residenza://'
 
 
Vedi un po'...
Se non torna qualcosa eventualmente manda il file, come avevi fatto
la volta precedente, che ci do un'occhiata...
 
 
 
Saulti!  :)

Il Tue, 02 Jan 2018 14:44:45 +0100, Joe ha scritto:
 
[...]
 
Ciao Joe, 
prima di tutto, voglio ringraziarti, perché mi hai fatto un grande regalo 
di Natale. Mi hai fatto conoscere sed e più precisamente:
 
1) Trasformare un pdf in txt con lo stesso layout;
2) Estrapolare solamente le stringhe richieste;
3) Copiarle in un file temporaneo esterno;
4) Copiare il tutto in un unico file txt;
 
Bellissimo!!
 
Ora tornando al problema del layout non omogeneo:
;ROSSI                        MARIO; VIA ROMA,45
;ROSSI                        ROMEO; VIA GARIBALDI,37
;NERI                        FRANCO; VIA MILANO,36
;VERDI                       CINZIA; VIA TORINO,21
 
ho parzialmente risolto facendo prove con il numero all’interno delle 
graffe (ultima riga):
grep -B1 'Nato a' $CONVERTED \
 |sed /^Nato\ a/,/^--$/d \
 |sed 's/^[0-9]*\s\(.*[A-Z]\)\s*[M,F]$/\1/' \
 |sed 's/\s\{5,\}/;/' > tmp-nomi.txt 
 
Aumentando anche di un solo punto il 5, portandolo a 6, ottengo:
|     Rossi;Mario;Via Roma, 5
|     Neri;Lucia;Via Garibaldi, 6
|     Verdi;Giovanni;Via Milano, 7
 
Ottengo un layout quasi perfetto, con solamente delle degli spazi vuoti, 
prima del cognome, che potrei eliminare con la funzione =Annulla.Spazi(A1) 
una volta importato il txt in Calc.
 
Ma poiché mi piace fare le cose perfette, ti allego il link del file pdf 
originale, così puoi darci un occhio.
 
PDF:
https://drive.google.com/open?id=15KZpxN7qVLfUaRzl_1_JReYQS44Zv09X
 
 
Script:
https://drive.google.com/open?id=1KRLnpQRzj5bj2ycr9bNtGhhuUAnF0tOP
 
 
 
===============
Domanda:
 
Da quando mi hai risposto la prima volta al post (29-12-2017), sto 
cercando dei tutorial in internet che spiegano il comando sed. Poichè non 
sono più giovane e altre cose nella vita …. ho bisogno di imparare-
elaborare sed a piccoli passi o a piccole dosi. 
 
Il consiglio che mi hai dato di spezzettare lo script, mi è piaciuto, 
perché è come avere dei piccoli segmenti di codice componibili da usare 
in futuro. 
Ma ho bisogno di capire e commentare lo script, in questo modo mi 
costruisco il mio tutorial, sulle mie esigenze reali.
 
Oltre a questo, ho bisogno di un tuo consiglio per migliorare 
l’apprendimento e la costruzione del tutorial.
 
Grazie in anticipo e Auguri di un Interessante e Buon Anno,
Ciao, 
Nemo
 

  |sed 's/\s\{5,\}/;/' > tmp-nomi.txt 
 
Ma l'errore non era lì...
Te lo avevo scritto nel post precedente e avevo
azzeccato anche l'inghippo. Dacci una rilettura.
 
L'errore salta fuori perchè nella riga del nome tra
il numero iniziale di 5 cifre (immagino sia un iden-
tificativo o qualcosa di simile) e la prima lettera
del COGNOME ci sono diversi spazi... diciamo uno o
più spazi, un numero arbitrario ecco.
Per intercettare questo pattern in sed si usa il
carattere "spazio" che viene esplicitato da "\s"
seguito dal carattere asterisco "*", che indica che
il carattere che lo precede (cioè lo spazio) è ripetuto
una serie indefinita di volte (anche zero volte, se non
sbaglio, eventualmente cercati con google questo parti-
colare per conferma):
 
\s ----> uno spazio
 
\s* ---> uno o più spazi
 
Quindi in conclusione la riga errata è la penultima
di quelle lì sopra che ho riportato:
 
|sed 's/^[0-9]*\s\(.*[A-Z]\)\s*[M,F]$/\1/' \
 
e va corretta come segue:
 
|sed 's/^[0-9]*\s*\(.*[A-Z]\)\s*[M,F]$/\1/' \
                 ^
		qui
		sopra
		c'è un
		asterisco!!!
		che prima mancava...
 
 
Con questa modifica a me funziona...
Però, per fare il parse dell'indirizzo di residenza c'è un modo più
semplice di come hai fatto tu:
nel file dell'altra volta, 1NASCITE.pdf avevamo dovuto cercare
l'indirizzo di basandoci sulla riga "successiva" al pattern
Residenza... quindi avevamo dovuto poi ancellare le due righe
in più che stampa "grep" e quindi sfoltire con "sed".
 
Nel caso di questo nuovo file immigrati.pdf
 
L'indirizzo di residenza sta sulla stessa riga del pattern da
cercare "Residenza". Quindi basta dire a sed di prendere
le righe che iniziano per "Residenza:" e rielaborarle facendo
il parse dell'indirizzo. Il tutto si può fare senza bisogno di
"grep":
 
sed -n 's/^Residenza:\s*\([A-Z].*[0-9,a-z,A-Z]\)\s*$/\1/p' \
       $CONVERTED > tmp-indirizzi.txt
 
l'opzione -n dice a sed di non stampare tutto il file
modificato. La "p" in fondo dopo la sostituzione fa sì
che le righe rielaborate e solo quelle vengano stampate
"p" sta per "print".
La mia backslash ce vedi lì sopra, è per accorciare la
riga... puoi anche toglierla e scirvere tutto su una riga
nello script.
Nota che dopo i due punti seguenti "Residenza" ho messo
nel pattern lo spazio ripetuto uno o più volte "\s*",
prima di intercettare la stringa dell'indirizzo, così
il risultato finale non salta fuori con spazi inutili.
 
Riguardando i PDF che hai mandato noto che le uniche righe
che iniziano con un numero sono quelle contenenti cognome
e nome.
Pertanto era più facile anche fare il parse dei nominativi
senza andare a cercare la riga "Nato a:" e prendere quella
precedente con "grep -B1".
 
Infatti prova a prendere il file testuale e fare:
 
grep ^[0-9] convertito-temporaneo.txt
 
Vedrai cosa salta fuori...
Hai provato?
Hai capito come si poteva fare il parse in modo più semplice?
Provaci che poi ti mando lo script corretto e semplificato.
 
Ho superato le 100 righe... qua mi fermo.
Per l'altra domanda sui tutorial ti rispondo in altro messaggio.
Ciao

 Grazie in anticipo e Auguri di un Interessante e Buon Anno,
 
Altrettanto, ricambio gli auguri!  :)
 
Un tutorial preciso su sed, grep ecc ecc non saprei consigliartelo
io stesso ho imparato molto a tentoni cercndo "how to" specifici
per quello che mi serviva di volta in volta.
Trovo molto utile la community 
unix.stackexchange.com
 alla quale
giungo spesso via google ricercando cose tipo:
 
sed print just substitution lines
 
tanto per dire una chiave di ricerca che ti porta ad un topic
in cui un tizio chiedeva come far si che sed stampi le sole
righe che ha modificato con una una sostituzione.
 
(sed -n 's/pattern/sustitution/p').
 
Anni e anni fà avevo anche leggiucchiato la ABS di mendell cooper:
 
http://tldp.org/LDP/abs/html/
 
 
Si trova anche in italiano:
 
http://www.pluto.it/files/ildp/guide/abs/index.html
 
 
Contiene le basi per programmare la shell Bash, utilissima
per fare gli script come questo che abbiamo visto. Tieni
conto che se impari ad usare i comandi di sistema e sai
programmare un po' in bash, riesci a fare molte ma molte
cose personalizzatissime... Non solo rimaneggiare dei files
di testo, ma anche per controllare il comportamento del
sistema: gli script bash automatizzano il controllo di comandi
che hai sul sistema, applicazioni varie, comunicazione con
l'hardware, supportano operazioni condizionali, cicli ecc...
Insomma puoi farci bellissimi accrocchi, ma talvolta hanno
un'utilità e una potenza notevoli.
 
In quelle guide c'è un capitolo dove spiegano un po'
di "lavorare col testo" e lì accenna a grep, sed e
anche awk.
 
Non penso che sia la guida migliore, ma puoi usarla per
un'infarinatura. Poi mano mano che crei degli scripts, ti
fai l'esperienza che manca. Alla fine poi quando hai un
dubbio secondo me resta sempre più rapida una ricerca alla
bisogna e al limite uno scambio di idee, qui o in altri
forum. Lì trovi anche chi ti da qualche dritta esplicativa,
io avevo imparato molto soprattutto così, almeno per quel
che mi serve.
 
Ad ogni modo ho provato a cercare:
 
sed tutorial italiano
 
in google e trovo tra gli altri:
 
http://www.pluto.it/files/ildp/guide/abs/sedawk.html
 
https://natonelbronx.wordpress.com/2007/12/02/sed-programma-per-manipolare-e-filtrare-flussi-di-testi/
 
http://digilander.libero.it/jacknake/informatica/manipolation-text/lavori-sed/guida-sed01SP.html
 
 
In inglese:
https://www.gnu.org/software/sed/
 
https://www.gnu.org/software/sed/manual/sed.html
 
https://www.digitalocean.com/community/tutorials/the-basics-of-using-the-sed-stream-editor-to-manipulate-text-in-linux
 
 
E tante altre...
Se vuoi partire dall'analisi dello scriptino che ti ho proposto
per il parse del PDF. Prova a descrivere cosa fa ciascun comando
e in che modo. Descrivi di preciso i "pattern" coinvolti da sed,
e da "grep", perchè poi alla fine la difficoltà è tutta lì:
 
anzi spetta che ti metto un altro link sulle espressioni
regolari "REGEX":
https://www.regular-expressions.info/
 
 
Come avrai capito sono queste il nocciolo del trattamento
del testo per intercettare ("match" in inglese) le righe
e modificarle.
Ciao

 Per l'altra domanda sui tutorial ti rispondo in altro messaggio.
Aspetto il tuo consiglio!
Ciao,
Nemo
 


Con lo smartphone ho visto che mi hai anticipato. Ho visto la risposta 
dei consigli, mentre con Pan deve ancora arrivare.
 
Comunque, grazie per i tuoi *preziosi* consigli. Ti ringrazio tantissimo, 
per me è stata tutta esperienza nuova con grep e sed e mi ha aperto un 
mondo nuovo, che voglio conoscere!!!
Naturalmente ci metterò un pò di tempo...
 
Quando puoi, aspetto il confronto degli script.
Ciao, un cordiale saluto,
Nemo

 rm tmp-nomi.txt tmp-indirizzi.txt $CONVERTED
 
 
 
Questo è il mio tentativo (sono 7 righe):
----------
#!/bin/sh
INPUT=$1
CONVERTED=immigrati.txt
pdftotext -layout $INPUT $CONVERTED
sed -n 's/^[0-9]*\s*\([A-Z].*[A-Z]\)\s\{8,\}\([A-Z].*[A-Z]\)\s*[M,F]$/\1;\2/p' $CONVERTED > nomi.tmp
sed -n 's/^Residenza:\s*\([A-Z].*[0-9,a-z,A-Z]\)\s*$/\1/p' $CONVERTED | paste nomi.tmp - -d';'
rm nomi.tmp $CONVERTED
-----------------------
 
Nella pen'ultima riga ho usato il "paste" in pipe (in cascata al sed)
dandogli come primo argomento la colonna dei nomi (il file nomi.tmp
prodotto dal sed alla riga precedente) come secondo argomento fai caso:
gli ho dato un trattino "-".
Questo ha il significato di "standard input" cioè lo schermo. E siccome
a la pipe cioè la stanghetta "|" prende come input, l'output del sed a
sinistra, il nostro standard input è proprio l'output di sed, cioè la
colonna degli indirizzi.
 
- sed    :    input  = file-converted.txt
              output = colonna-indirizzi
 
- Pipe | :   standard_input di quello che segue = standard output
             di quello che predede ovvero sed = colonna-indirizzi
 
- paste  :   input1 = nomi.tmp (la colonna COGNOME;NOME)
             input2 = - (lo standard input, ovvero la colonna indirizzi)
 
Questo espediente consente di risparmiare la scrittura sul file
"tmp-indirizzi.txt" che come vedi è sparito. Usiamo solo due files
in questa soluzione.
L'opzione -d';' di paste penso che sia già chiarita la volta scorsa.
"man paste" per toglierti eventuali dubbi.  ;)
 
 
Ti propongo un'altra soluzione ancora, sempre sulla falsariga
di usare ancora un file di appoggio in meno.
Ma posterò un altro messaggio per lo scopo altrimenti facciamo
confusione. Hai già fin troppo materiale da digerire, concentrati
sul riconoscimento del pattern osservando la struttura delle righe
e traduci i pattern in regexp espressioni regolari.
 
Buono studio!  :)

 di usare ancora un file di appoggio in meno.
 
 
Ecco... Come dicevo si potrebbe fare anche così:
------------
#!/bin/bash
INPUT=$1
CONVERTED=immigrati.txt
pdftotext -layout $INPUT $CONVERTED
paste -d\; \
        <(sed -n 's/^[0-9]*\s*\([A-Z].*[A-Z]\)\s\{8,\}\([A-Z].*[A-Z]\)\s*[M,F]$/\1;\2/p' $CONVERTED) \
        <(sed -n 's/^Residenza:\s*\([A-Z].*[0-9,a-z,A-Z]\)\s*$/\1/p' $CONVERTED)
rm $CONVERTED
--------------
 
Però non è POSIX compatibile, quindi non funziona
se si interpreta con la shell "sh", serve la "bash".
Il comando paste è tutto su una riga anche se per leggibilità l'ho
riportato su tre righe.
Questa soluzione consente di avere un solo file di appoggio,
cioè il pdf convertito in testuale.
 
Le "strane" strutture tra parentesi precedute dal simbolo "minore di"
sono indicate come "process substitution":
https://www.gnu.org/software/bash/manual/bashref.html#Process-Substitution
 
 
Nel caso sopra "paste" prende gli output dei due comandi sed come
due argomenti, come fossero due files da incollare...
 
 
Ora a parte la soluzione alternativa da proporre all'OP  Nemo
questo mio messaggio vorrebbe essere anche una domanda agli
espertisssimi utenti di "shell scripting", che bazzicano qui
su icoli e che magari possono aiutarmi in un dubbio:
nello script precedente resta comunque un file di appoggio,
il file $CONVERTED. Ma ho pensato ad un fantasioso processo
del tipo seguente che porterebbe direttamente all'output
finale senza files di appoggio.
Al di la del file di appoggio, volevo sapere si si potrebbe
fare una cosa del genere:
 
 
                ---> sed_nomi ------->
              /                        \
pdftotoext --                           -----> paste out-nomi out-indirizzi
              \                        /
                ---> sed_indirizzi -->
 
 
La domanda è:
- posso prendere l'output di un comando
- redirigerlo contemporaneamente su due
  flussi diversi
- da elaborare ciascuno indipendentemente
- e ottenere così due output diversi
- da riutilizzare di nuovo sullo stesso processo
 
???
In rete ho trovato accenni a "tee", "file decriptors"
e altre diavolerie... Ma francamente non penso siano
sufficienti per fare questa roba che ho schematizzato
sopra.
 
Cosa ne pensate? Qualcuno senz'altro ci avrà già
ragionato e lavorato...
Mi sapreste aiutare?
Grazie in anticipo!   :)
 
 
 
 

Nemo 20:32, giovedì 28 dicembre 2017:

man pdftotext
 
 
-- 
AIOE °¿°  
Ho plonkato tutti quelli che postano da Google Groups!
Qui è Usenet, non è il Web!

 Grazie in anticipo!   :)
 
Nessuno ha qualche idea o soluzione a portata di mano?
 
 
PS.
Ho cambiato titolo al topic

 Nemo <interpocu...@lescarpeoccupato.it.invalid> wrote:
Ciao Joe, 
 
finalmente ho un pò di tempo per rispondere.

Grazie mille per la chiave di lettura della sintassi - legenda. me la 
studierò per bene.

Ho provato questa versione, ma non produce nessun file immigrati.txt.
 
Funziona solamente se commento l'ultima riga #rm nomi.tmp $CONVERTED.
 
Cioè, inibendo con il simbolo # il comando "rm", il file immigrati.txt 
viene costruito e popolato con le colonne Cognomi;Nomi;Indirizzo, 
ma subito dopo,  viene accodato il CONVERTED e cioè il tmp-converted 
(file.txt con lo stesso layout del pdf).
 
Per cui ho 2 file in uno, dove la seconda parte è ridondante.
 
Tutto sommato, anche se il grep non servirebbe, la sua presenza porta al 
file finale immigrati.txt, completamente pulito e popolato in una 
frazione di secondo.

Grazie, certamente sarà materia di interesse, perchè go visto che si 
possono ottenere risultati stupefacenti.
 
Ciao,
Nemo
 

 la shell "sh", serve la "bash".
 
Il bash che dici, deve essere inserito nell'estensione del file
parse-immigrati.bash  ???
 
Ciao, 
Nemo

 Grazie in anticipo!   :)
 
Ovviamente, una soluzione banale:
 
cat file |
while read LINE
do
  N=$( echo $LINE | sed_nomi )
  I=$( echo $LINE | sed_indirizzi )
  echo $N $I # oppure come piu` piace
done
 
Questo funziona *abbastanza*, ma vi possono
essere controindicazioni.
Ma non e` parallelo, chiaramente.
 
bye,
 
-- 
 
piergiorgio

 Ho provato questa versione, ma non produce nessun file immigrati.txt.
 
Infatti non deve produrre alcun file immigrati.txt
Quello è un file temporaneo che poi prendono in input le operazioni
di parse dei noi e degli indirizzi.
 
Prima di tutto, da come hai quotato vedo che hai qualche impostazione
nel tuo newsreader che fa casino...
Visualizza il topic da google gruppi per verifica: il mio non era
scritto in quel modo, ci sono degli "a capo" che vanno mantenuti,
se no non funziona...
Lo trovi anche qua:
https://groups.google.com/forum/#!original/it.comp.os.linux.iniziare/p6llT-WNvlc/Kzypq0nRBQAJ
 
 
Inoltre, posto che tu l'abbia copiato correttamente come lo hai lanciato?
 
Lo script non produce alcun file finale, usa due file di appoggio che
come hai osservato vengono rimossi alla fine delle operazioni.
Ti satmapa però a video direttamente il CSV finale che ti serve.
 
Ovviamente se vuoi puoi redirigere lo standard output (cioè lo schermo)
su un file con l'operatore *maggiore*: ">"
 
Puoi lanciarlo come segue:
--------------------------------------------------------
nome_script nome_file_di_input.pdf > tabella-finale.csv
--------------------------------------------------------
 
Mi pare che anche nei post passati lo avevi lanciato così...
 
Quindi ricontrolla il tutto, sistema il news reader ecc, perchè l'ho
testato e ti confermo che funziona, ecco l'output:
---------------------------------------
$ ./parse-immigrati-2.sh immigrati.pdf 
ROSSI;MARIO;VIA ROMA n. 3
NERI;LUCIA;VIA PICASSO n. 7
VERDI;GIOVANNI;VIA MONET n. 5
MAZZINI;GIUSEPPE;VIA CREMONA n. 74
ROMERO ALVAREZ;FRANCISCA MARIA;VIA CAVOUR n. 9
ROSSI;FRANCESCA;VIA FALCONE n. 5
---------------------------------
 
Ovviamente se vuoi che venga stampato quell'output su file CSV
invece che a video, come già detto:
-------------------------------------------------------
$ ./parse-immigrati-2.sh immigrati.pdf > immigrati.csv
$ cat immigrati.csv
ROSSI;MARIO;VIA ROMA n. 3
NERI;LUCIA;VIA PICASSO n. 7
VERDI;GIOVANNI;VIA MONET n. 5
MAZZINI;GIUSEPPE;VIA CREMONA n. 74
ROMERO ALVAREZ;FRANCISCA MARIA;VIA CAVOUR n. 9
ROSSI;FRANCESCA;VIA FALCONE n. 5
---------------------------------
 
Tutto chiaro?
Ciao!  :)

 parse-immigrati.bash  ???
 
No!!!!
L'estensione dello script non ha importantza.
Mi riferivo al richiamo all'interprete in cima allo script:
 
#!/bin/sh
 
Così richiami "sh" che non supporta la "process substitution":
 
<(sed bla bl bla)  ---> sta roba non funziona se in cima hai "#!/bin/sh"
 
Invece devi richiamare esplicitamente "bash": cioè in cima allo script
metterai:
 
#!/bin/bash
 
Tutto lì.
PS.
Ti avevo spiegato per filo e per segno quel comando, ricordi?
vai a rivederti il topic...
 
Ciao!  :)

 done
 
Eh ma perdiamo un po' troppo in efficienza mi sa, a causa
del read riga per riga: questo sed diretto sul file lo fa
molto più rapidamente...
Ad ogni modo come dicevi va un po' fuori dal seminato rispetto
alla domanda e allo schemino che avevo proposto.
 
Ad ogni modo, grazie Piergiorgio!  :)
Se ti viene in mente altro leggo con piacere!
Ciao!

 O era una cosa "chiusa".
 
 
C'entra qualcosa questa roba?
 
http://www.kossboss.com/?p=2794
 

 molto più rapidamente...
 
Di nuovo, se cerchi efficienza, devi scrivere
un programma in C.
 
Gli script sono comodi e veloci da scrivere, ma
sicuramente lenti da eseguire.
 
Ovvio che c'e` lento e lento, ma non mi porrei il
problema subito, a meno che non si riveli come tale.
 
bye,
 
-- 
 
piergiorgio

 cambia l'ordine, ovviamente.
 
Scusa ma non l'ho capita...

 Scusa ma non l'ho capita...
 
"cat" di fatto e` "concatenate", per cui riattacca
i due stream, solo che sono prima uno e poi l'altro,
non a linee alterne.
 
bye,
 
-- 
 
piergiorgio


Eh già... invece a me servirebbero in parallelo,
in modo che paste li incolli correttamente.
Ma anche al di là paste è il concetto cambia:
 
lì cat prende due files in input
li concatena
stampa il contenuto in un unico output (lo stdrd out)
che poi viene rediretto su file3
 
in questo esempio non vedo l'attinenza al discorso
dell'output sdoppiato...

 dell'output sdoppiato...
 
Devi o no ricongiungere i due stream?
Oppure ho capito male?
 
Come devono essere ricongiungi?
Per linea? Per carattere? Per file?
Per "paragrafo"?
 
bye,
 
-- 
 
piergiorgio


Nel caso di esempio, cioè
 
paste file1 file2
 
devono essere ricongiunti linea per linea,
ma è paste a leggerli linea per linea...
Il difficile è quindi darglieli "in parallelo".
L'esempio di cat invece come dicevo:
prima incolla in serie i due stream, concatenandoli
uno in coda all'altro. E genera così un unico output
finale... in cui i due stream distinti non sono più
utilizzabili.
 
Cosa succede usando i files di appoggio?
 
1 comando-iniziale > tmpfile-0
2 comando-1 < tmpfile-0 > tmpfile-1    # <--- Stream 1 
3 comando-2 < tmpfile-0 > tmpfile-2    # <--- Stream 2
4 comando-finale tmpfile-1 tmpfile-2   # <--- Ricongiungo stream
5 rm tmpfile-{0,1,2}
 
In pratica al comando 1 memorizzo l'output iniziale
(in questo caso su file) in modo da poterlo poi usare
come input per N "flussi operativi" (in questo esempio 2).
I due "stream" prendono in ingresso ciò che è stato
memorizzato e lo rielaborano, ciascuno indipendentemente.
Non solo, ma memorizzano a loro volta i rispettivi output
su due locazioni distinte (due diversi files di appoggio
temporanei). Il tuo esempio con "cat" non esegue questo
passaggio. È proprio in firza di questo che poi posso
tichiamare ciascun output di questi "flussi operativi" e
utilizzarlo in modo specifico (in questo caso usandoli
come argomenti di paste, nota che posso anche scegliere
l'ordine, cioè quale usare come primo argomento e quale
come secondo...
Insomma, coi files di appoggio si possono fare grandi
cose!
Spero, grazie a loro di essere riuscito a spiegarmi meglio
anche in termini di "concetti".
La mia domanda era sriuscire a eseguire questi passaggi
senza usare files di appoggio.
Ma non solo per ottenere l'output finale che voglio...
quanto proprio per replicare questo schema di funzionamento:
 
                    | flusso 1 --> out1
comando --> out0 -->| flusso 2 --> out2 --> comando (out1,N) --> last-out
                    | flusso N --> outN
 
 
Ok, mi pare chiaro lo scopo della fazzenda a questo punto
tuttavia, mi sa che non si possa proprio fare...
Stavo guardando i "custom file descriptors", ma non trovo
l'esempio giusto che mi aiuti a capire come eventualmente
sfruttarli per lo scopo.
 
Va bè, grazie per le risposte in ogni caso, almeno per
l'appoggio morale  :)
Ciao!