notepad
Notepad++ per la manipolazione\correzione di testi.
Art. di A. Buffolino inoltrato da S. Ciccarelli su smanettando, 18\05\2014, h. 07.50.

A beneficio dei compagni di lista e dei lettori di PCCiechi, mi permetto di inviare un articolo particolarmente interessante scritto da Alberto Buffolino.
Si tratta di un'alternativa validissima per la correzione/manipolazione di testi di studio o lettura.
Grazie, Alberto.
***
Vi illustrer abbastanza brevemente le tecniche adottate per sistemare l'ultimo testo inviato in lista, di cui trovate una copia non corretta qui (per verificare le spiegazioni):
https://dl.dropboxusercontent.com/u/9003469/AvEA.zip
Come scritto in oggetto, ho fatto uso di Notepad++, software gratuito che supporta file di testo sia ANSI sia Unicode, pi che altro orientato alla programmazione, ma poco c'importa; ne trovate una versione portable qui:
http://portableapps.com/apps/development/notepadpp_portable
Dopodich, importante premessa: sar estremamente lungo, ma in ogni caso non esaustivo, perch le regex sono molto varie, e le tecniche adottabili di volta in volta dipendono dallo stato del libro, da quanto si  disposti a correggerlo senza leggerlo o piuttosto a correggerlo via via con regex molto pi specifiche di quelle da me usate sotto. Vi raccomando inoltre di usare una barra Braille o di impostare temporaneamente la voce perch legga tutta la punteggiatura, fondamentale in quanto segue. Anche lavorare su una copia del documento anzich sull'originale  caldamente raccomandato.
Intanto, con regex, abbreviazione di regular expression (espressione regolare), intendo una stringa formata in un certo modo che dice al programma, ad esempio, di cercare allo stesso tempo tutte le lettere dalla a alla z, o tutti i numeri da 0 a 9, eventualmente ripetuti a formare una parola/numero pi grandi; per fare un esempio semplice, con una regex saremo in grado di cercare contemporaneamente i numeri 0, 1, 999, 1010 e cos via, oppure, con altra regex, tutte le parole che iniziano con p e finiscono con a. In Notepad++ useremo infatti la ricerca (control+f) e la sostituzione (control+h) impostata su espressione regolare, e con la casella relativa alle minuscole/maiuscole attiva (questa opzione non  sempre necessaria).
Ora, alcune notazioni:
si usano le parentesi quadre, [], per indicare un gruppo; esempi:
[a-z] indica tutto il gruppo delle lettere dalla a alla z, minuscole (notare il trattino fra la a e la z che identifica un range, un intervallo);
[A-Z] come sopra, ma maiuscole;
[0-9] tutti i numeri da 0 a 9;
ma possiamo anche comporre gruppi a nostro piacere, ad esempio:
[a-z0-9] tutte le lettere minuscole dalla a alla z e i numeri da 0 a 9 (notare che la z  attaccata allo 0);
[a-zA-Z,.;:?!"] tutte le lettere minuscole e maiuscole dalla a alla z e i principali segni di punteggiatura.
Per aiutarvi nella comprensione dei gruppi, guardateli da questo punto di vista: al programma voi dite "se quanto trovato corrisponde a uno qualsiasi dei caratteri inclusi nel gruppo, allora  un risultato della ricerca".
Tuttavia, i gruppi per come descritti non sono sufficienti, nel senso che con tali gruppi noi possiamo marcare solo un carattere, qualunque esso sia; dobbiamo introdurre il concetto di ripetizione per poter trovare una parola intera, o un numero pi grande di 9, abbiamo infatti:
+ a indicare un numero da 1 in su di occorrenze, esempio:
[a-z]+ significa che la ricerca trover tutte le sequenze di caratteri inclusi nel nostro gruppo (quindi nelle lettere dalla a alla z), ripeto sequenze, non pi un solo carattere; se quindi c' una parola racchiusa fra virgolette, per esempio, la ricerca selezioner l'intera parola, ma non le virgolette;
{min,max} indica un range pi esatto di occorrenze, esempio:
[0-9]{2,3} trover tutti i numeri lunghi da 2 a 3 cifre, 10, 20, 111 ecc; come vedremo dopo, esiste anche una forma monca, ovvero col solo minimo o il solo massimo, esempio:
[0-9]{2,} trover tutti i numeri lunghi almeno due cifre (ma anche tre, quattro, ecc, visto che non abbiamo specificato una lunghezza massima (notare la virgola non seguita dal massimo)).
In Notepad++ tutto ci (gruppi e simboli di lunghezza) vengono racchiusi sempre fra tonde, quindi avremo:
([a-z])
([a-z0-9]+)
([chr]{2,3}) (sequenze casuali di caratteri c h r lunghe da 2 a 3, quindi ccc, ch, cr, ecc, come potete vedere qui non sfruttiamo un intervallo noto ma scegliamo noi cosa includere)
Infine, qualche simbolo speciale:
\r e \n indicano rispettivamente il simbolo di carriage return e nuova linea, che generalmente noi percepiamo come uniti nell'indicazione di nuova linea; generalmente si ha un \r seguito da un \n, ma visto che questo non accade sempre, consigli di usare:
([\r\n]+) per identificare nuove righe (quindi accapi, e sostituire con:
\r\n quando si vuole ottenere una nuova riga;
\t indica il simbolo di tab.
Ci ampiamente premesso, apriamo il nostro txt. Per buona norma, eliminiamo le righe vuote superflue lasciandone al massimo solo una, e tutti gli spazi a inizio e fine riga; per le righe vuote superflue procediamo cercando:
([\r\n]{2,}) e sostituendo con:
\r\n\r\n (ricordate che \r\n una sola volta vi d una nuova riga, in cui per ottenere una riga vuota dovrete ripeterlo due volte)
Per gli spazi, dividiamo l'operazione in due; per primi, affrontiamo gli spazi a inizio riga, per cui, tenendo conto che prima di tale spazio potrebbe esserci un accapo come due (riga vuota), cercheremo:
([\r\n]+)
(dopo la chiusa tonda c' uno spazio), sostituendo con:
\1
che significa semplicemente che al posto di quanto trovato verr sostituita la parte trovata grazie a quanto specificato nelle parentesi tonde, e cio le eventuali righe vuote trovate.
Per gli spazi a inizio riga, con ragionamento identico, cercheremo:
([\r\n]+)
(notare lo spazio a inizio riga) e sostituiremo con:
\1
che ha lo stesso significato di prima.
Ora conviene analizzare un po' il nostro documento, a partire dalla scritta "Parte I". Scorrendo, notiamo che ogni tanto ci sono dei numeri di pagina a dividere il testo, a volte con una riga vuota prima o dopo, a volte senza righe vuote n prima n dopo ma comunque a capo. Come forse qualcuno di voi ha gi intuito, per vedere tutto questo possiamo fare una ricerca dei soli numeri, cercando:
([0-9]+)
e scorrendo di F3 vari risultati all'inizio del libro e, per sicurezza, anche all'indietro (shift+f3) dal fondo del libro.
Naturalmente, questo ci serve solo per avere una panoramica. Potremmo anche gi decidere di cancellare i numeri di pagina basandoci sulla presenza di nuove righe prima e dopo, ma il nostro lavoro sarebbe alquanto pasticciato e poco gradevole. Vediamo anche, infatti, che, come prevedibile, i numeri a volte rimangono fra una parola spezzata con trattino e la sua continuazione, oppure fra un paragrafo che si conclude con un segno di punteggiatura definitivo (punto, punto interrogativo o esclamativo) o anche una virgoletta di fine discorso, nel qual caso il paragrafo seguente inizier con una lettera maiuscola, o con una virgoletta che inizia un nuovo discorso. Tralasciando il caso delle parole spezzate, e affrontando gli altri detti, possiamo concepire (dopo luuungo esercizio) il seguente mostro di regex:
([.?!"])([\r\n]+)([0-9]+)([\r\n]+)([A-Z"])
che tradotto significa: un punto, o punto interrogativo, o esclamativo, o virgoletta, seguito da una o pi nuove righe, seguito da un numero lungo a piacere (la pagina), seguito da una o pi nuove righe, seguito da una lettera maiuscola fra a e z oppure una virgoletta.
Cercando tale regex, e sostituendo:
\1\r\n\5
90 e passa numeri di pagina se ne vanno, lasciando i due paragrafi intatti ma uniti su una nuova riga. Notate che \1 si riferisce al primo gruppo fra tonde, \5 all'ultimo ( sufficiente contare le coppie di parentesi tonde per ricavare il numero).
Mi sono dimenticato di dire che  buona norma, prima di applicare una regex in questa maniera, cercarla (senza quindi sostituire niente) nel testo e marcare due o tre risultati con un simbolo particolare (io uso sempre @@), badando a non porre i simboli nel mezzo al testo intercettato dalla regex. Una volta applicata la regex con sostituzione, potremo cercare il simbolo e vedere se la sostituzione  stata fatta correttamente, in caso contrario siamo sempre in tempo ad annullare dal menu modifica.
Ora torniamo all'inizio del testo, diciamo a "Parte I", e cerchiamo di nuovo:
([0-9]+) per vedere di trovare altri casi interessanti per il numero di pagina. Vogliamo ora trattare il caso in cui il numero di pagina si trovi fra una riga che termina con una lettera minuscola di una parola completa, oppure con una virgola, e una riga che inizia con una lettera minuscola della parola successiva nel paragrafo spezzato dal numero di pagina, o anche una lettera maiuscola (potrebbe trattarsi di un nome). Concepiamo perci la regex:
([a-z,])([\r\n]+)([0-9]+)([\r\n]+)([a-zA-Z])
come vedete, cambiano solo gli estremi, mentre il corpo centrale, relativo al numero di pagina e nuove righe circostanti, rimane lo stesso. Cercando tale regex, e sostituendo:
\1 \5
otteniamo il nostro paragrafo riunificato su una stessa riga, con le parole divise da uno spazio. E un'altra ottantina di casi son stati trattati.
Andando avanti, ci rimane il caso delle parole spezzate; in questo, abbiamo una lettera minuscola seguita da un trattino, seguita dalle solite righe con numero di pagina seguite infine da una lettera palesemente minuscola, essendo la continuazione della parola interrotta prima. Cerchiamo perci:
([a-z])-([\r\n]+)([0-9]+)([\r\n]+)([a-z])
e sostituiamo:
\1\5 (stavolta senza spazio)
E altri 55 numeri di pagina se ne vanno.
Giunti a questo punto, ci potremmo accorgere, con grande scorno (come  stato per me), che malauguratamente al posto degli spazi a inizio o fine riga in alcuni casi ci sono delle tabulazioni, che ovviamente sballano le regex precedenti, senza contare il fatto (che regolarmente mi dimentico) che Notepad++ non include, nel range a-z, le lettere accentate della nostra lingua. Possiamo cancellare le tabulazioni sfruttando \t e due regex molto simili a quelle usate per gli spazi, quindi riapplicare le regex gi usate. Cercando poi \t nel resto del testo notiamo varie altre imperfezioni non connesse al numero di pagina, cos come cercando il simbolo  o due spazi consecutivi... ma questo esula dalle regex.
Per concludere, per assicurarci di aver pulito il testo dai numeri superflui ci conviene ri-eseguire di bel nuovo nuovamente la ricerca di:
([0-9]+)
ed eventualmente correggere a mano i pochi casi non gestiti dalle regex precedentemente applicate.
Mi rendo conto che tutto ci pu apparire mostruosamente cervellotico, ma in alcuni casi, con libri pi regolari, i problemi si risolvono molto velocemente, e in ogni caso le regex forniscono strumenti di correzione utili per veramente molte, molte occasioni. E non vi ho neppure illustrato tutte le caratteristiche...
Spero (ma  una tenue speranza) che qualcuno di voi sia riuscito ad arrivare fin qui senza scoraggiarsi, sono naturalmente disponibile per domande, in privato o in lista se il moderatore  d'accordo (penso che non ci siano problemi, visto che  un argomento decisamente per dannati dello scanner).
Buone... regex a tutti!
