Newsgroup: it.comp.lang.perl
Titolo: [RegExp]: Intercettare gli apici `singoli'

  Sembra una cazzata, ma non lo e`, almeno per me.
  Scusate la  lunghezza, ma  credo sia  opportuno capire  "il perche'"
della domanda...
  Sto  scrivendo  uno script  in  perl  di riformattazione  testo  dei
messaggi  scritti su  Usenet. Ovviamente  non e`  orientato a  tutti i
NewsGroup, ma ad  uno in particolare, che ha per  oggetto la scrittura
di  "testi pseudo-letterari".  Lo scopo  finale e`  quello di  rendere
alcuni testi il piu` possibile "stampabili" in modo da dover ricorrere
il meno possibile alle correzioni "a manina"... ;)
  Ora:  qualcuno usa  le accentate,  qualcuno invece  usa gli  `apici'
singoli (come  me, del resto), sia  per racchiudere un testo,  sia per
fare le  accentate. Tra  le altre  cose, tento  di uniformare  il piu`
possibile le  accentate, quindi se  trovo un "perche'" lo  modifico in
"perché", se trovo un "pero'" lo modifico in "però"...
  Ma provate a considerare queste quattro possibilita`:
1) sono andato sotto il 'pero'
2) sono andato sotto il `pero'
3) 'sono andato sotto il pero'
4) `sono andato sotto il pero'
  Secondo voi, come potrei capire che quel "pero" non e` un "però"?
  Cosi`, a "naso",  dovrei intercettare tutti i gruppi  compresi fra i
quattro gruppi di virgolette, sostituirli  con un codice apposito, poi
ripassare tutti gli apici con le  mie regolette, e poi ri-sostituire i
miei codici con gli apici originari...
  Volendo, una frase tipo
"'sta cosa non mi va, pero' [...]
  potrei intercettarla facilmente, visto che  oltre a "'sta", "'sto" e
altre  cosucce implementabili  successivamente,  la  casistica non  e`
molto vasta...
  Ma -  sempre che  l'ipotesi sia giusta  - qual e`  la regexp  che mi
consenta  di  ottenere  (virgoletta_iniziale)  (testo_compreso_fra_le_
virgolette) (virgoletta_finale)?
  Vi ringrazio per la pazienza...
NB: I  codici  "strani"  utilizzati   da  Windows  per  le  cosiddette
"virgolette inglesi" li ho gia` codificati. Non e` quello il problema.
-- 
Cio` che ho scritto, ho scritto.

 
Ma il problema e' come fare a dire che questa e' una frase con virgolette semplici:
--> ho detto: 'sono sotto il pero', hai capito?
mentre quest'altra no:
--> Ora pero' non ce la faccio piu'
Io userei questa tecnica:
1)
    prendi un dizionario di italiano e cerca tutte le parole che contengono
    una lettera accentata.
2)
    Per ognuna di queste parole ti fai una serie di possibili varianti con
    i vari apostrofi.
3)
    Con ogni variante della parola, ti costruisci un hash, avente per chiave
    la tua variante, e per valore quello accentato.
    esempio:
    "pero'" => "però",
    "pero`" => "però",
4) Per ogni parola con variante, cerca nello stesso dizionario, per verificare
    che non esista una parola uguale, ma senza accento (come pero' -> però -> pero)
5)
    Per tutte queste parole incontestabili (esempio: "perché" non ha un
    corrispondente "perche"), esegui un primo giro di sostituzioni,
    utilizzando l'hash.
6)
    Esegui un secondo giro, verificando per ogni caso dubbio se ci siano delle
    virgolette in giro per la frase. (usando la regexp di cui sopra). Se ce ne sono,
    verifica se entrambe le virgolette appartengono a una parola "dubbia". Se una
    delle due non e' dubbia, e' probabile che si tratti proprio di virgolette.
    Se entrambe le virgolette sono vicine a una parola "dubbia", le marchi per
    una revisione manuale.
In tutto questo, devi considerare che ci sono anche gli apostofi: l'amaca, l'amica,
dell'acqua, dall'altra, ecc. Dovresti eliminare questi apostrofi legittimi,
facendo un giro di sostituzioni prima di affrontare quello del punto 5.
E' un po' complicato e non e' nemmeno perfetto e onnicomprensivo, ma che ci vuoi fare?
La lingua e' complicata. L'alfabeto e' limitato, il computer e' stupido. :)
Buona fortuna!
Ciao
gmax
-- 
   ____ ____  _____ _   _
  / _  |    \(____ ( \ / )
( (_| | | | / ___ |) X (
  \___ |_|_|_\_____(_/ \_)
(_____|
MySQL Certified Professional
Sapere, saper fare, fare, far sapere
http://gmax.oltrelinux.com

facendo un giro di sostituzioni prima di affrontare quello del punto 5.
Non vedo perché, gli apostrofi sono la cosa più semplice da riconoscere
(niente spazi, né prima né dopo). Tanto, bisogna togliersi dalla testa che
si riesca risolvere senza un'analisi del contesto (con lookahead,
lookbehind e quant'altro). E bisogna rassegnarsi al fatto che non si
risolve con una manciata di espressioni regolari: bisogna scrivere un
parser, per quanto magari minimale.
Innumerevoli anni fa (lo usavo per i messaggi FidoNet) scrissi un filtro in
lex che funzionicchiava. All'epoca però, su FidoNet, non c'era la
variabilità di comportamento che si ha ora su Usenet: i caratteri accentati
non erano consentiti e basta. In ogni caso, non credo di poter recuperare
il filtro. 
Ciao.

 (apice1, $testo, $apice2) = (regexp_che_non_riesco_a_scrivere);
  Mi basterebbe e avanzerebbe!... :(((


> (apice1, $testo, $apice2) = (regexp_che_non_riesco_a_scrivere);
E' proprio questo che io reputo difficile, macchinoso, fragile e non
conveniente, dove non impossibile. Infatti, non a caso non ci riesci.
Già l'espressione regolare che usi per i link è ottimistica, e può essere
fatta fallire. E sei facilitato dal fatto di trovarti in un contesto
fortemente strutturato, come l'html. Nell'ambito di un linguaggio naturale,
la situazione è ancora più complessa.
Ripeto la mia valutazione: difficilmente se ne viene fuori senza
rassegnarsi a costruire un parser, o almeno un analizzatore lessicale, del
linguaggio; un'unica espressione regolare è molto facilmente destinata a
fallire in un numero non trascurabile di casi.
E', per esempio, secondo me, meglio, oltre che molto più semplice, andare
avanti a leggere finché non si incontra un apice (in un contesto in cui
deve, o almeno può, essere un apice, cioè, in prima analisi, preceduto da
uno spazio), entrando nello stato "citazione", e si procede in questo stato
finché non si incontra l'apice di chiusura (in un contesto in cui deve, o
almeno può, essere un apice di chiusura, cioè, in prima analisi, seguito da
uno spazio o un carattere di interpunzione). Non escludo che questa possa
anche essere la traccia per la costruzione di un'espressione regolare,
perché Perl consente questo genere di cose, ma io eviterei di risolvere in
questo modo, per i motivi detti.
Ciao.

 qualcheccosa?
Sono standard e implementate dentro al linguaggio. Pero` sono un po'
difficili da scrivere. Quindi e` stato fatto Regexp::Common, che e`
una collezione di RE per i piu` disparati usi. Ti rimando ad un paio
di link:
  * 
http://search.cpan.org/~abigail/Regexp-Common-2.120/
    La documentazione
  * 
http://www.isogest.org/cgi-bin/igwiki/RegexpCommon
    Una piccola recensione, con un esempio
Considera il fatto che puoi usare Regexp::Common esattamente come
una "cassetta degli attrezzi", ovvero prelevando le RE che ti
interessano, e solo quelle, senza includere tutto il modulo nei
tuoi programmi. Per dire:
  $ perl -MRegexp::Common -e 'print $RE{delimited}{-delim=>"/"}'
  (?:(?:\/)(?:[^\\\/]*(?:\\.[^\\\/]*)*)(?:\/))
Questo per Regexp::Common. Mi sembrano comunque ragionevoli le
obiezioni di Zezza, nell'altro ramo del thread.
ciao,
S.
-- 
Stefano Rodighiero      |  
http://larsen.perlmonk.org/blog
mailto:
lar...@perl.it
   |  
http://www.perl.it

 strutturato, come l'html.
  Eccerto! Senno` che la scrivevo a fare?
  Cmq, ripeto: io non sto cercando  la "soluzione finale". Il tutto e`
"finalizzato" a  un certo tipo  di post, non "all'Universo  Mondo". Ti
devo  dire che  questo  problema -  statisticamente  - e`  "marginale"
rispetto  al  filtro  che  ho  gia` attuato.  Volevo  solo  provare  a
"intercettare"  anche questa  "eventualita`".  Il filtro  che ho  gia`
attuato mi  consente di "capire"  dove sbaglia. Se  "sbagliera`" anche
dopo, non e` quello il problema. L'importante e` che "sbagli di meno".
  Cerco di spiegarmi meglio.
  E`  completamente  lungi da  me  l'idea  di  creare uno  script  che
corregga "tutto",  ok? Cerco solo  di creare uno "strumentino"  che mi
consenta di intervenire "a manina" il meno possibile.
  E quello "strumentino"  gia` ce l'ho. Cercavo  solo qualche `dritta"
per intercettare questi "casi", intesi come "casi `standard'".
  Volendo, la "casistica" mi puo` suggerire alcune "varianti"... ma il
problema di fondo e` quello di "uniformare" il piu` possibile un testo
che  non e`  la  "classica"  Domanda/Risposta a  un  NewsGropu, ma  un
"Racconto", capisci? Quindi la "casistica" viene ridotta.
  Io non  cerco di trasformare  un post  di iclp, perche'  non avrebbe
senso.


> (apice1, $testo, $apice2) = (regexp_che_non_riesco_a_scrivere);
  Sbagliato:
  dovrei avere una cosa del tipo
  ($fuffa1, $apice1, $testo, $apice2, $resto) = (regexp);
  In modo  da poter  eliminare "fuffa1",  di poter  elaborare "apice1,
testo, apice2", e di poter elaborare in seguito il "resto".
  Credo stia qua l'inghippo che non riesco a risolvere.


"Racconto", capisci? Quindi la "casistica" viene ridotta.
La mia idea al proposito l'ho detta: si va avanti a leggere finché non
si incontra un apice (in un contesto in cui deve, o almeno può, essere
un apice, cioè, in prima analisi, preceduto da uno spazio), entrando
nello stato "citazione", e si procede in questo stato finché non si
incontra l'apice di chiusura (in un contesto in cui deve, o almeno
può, essere un apice di chiusura, cioè, in prima analisi, seguito da
uno spazio o un carattere di interpunzione).
Strategia, come vedi, anche più semplicistica di quella da te
proposta, ma che insomma può costituire un inizio. Prima, dopo o
durante, si aggiustano alcuni casi particolari, e nell'insieme si
spera che ne salti fuori qualcosa di ragionevolmente buono nella
maggior parte dei casi.
Incredibilmente, ho recuperato il sorgente flex del programmucolo che
scrissi nel lontano 1995, e che immagino implementi questa strategia
(sebbene di flex mi ricordi molto poco del già pochissimo che sapevo
all'epoca, sicché mi è difficile dire che cosa effettivamente faccia):
    %x EST
    %x CI
    %x QUOTE
    %%
    (([ \t]+|\n)(mo'|po'|da'|de')) printf("%s", yytext);
    a('|`) printf("%s", "\x85");
    che('|`)  printf("%s", "ch\x82");
    ([ \t]+)('|`) printf("%s", yytext); BEGIN(QUOTE);
    ^('|`) printf("%s", yytext); BEGIN(QUOTE);
    <QUOTE>('|`) printf("%s", yytext); BEGIN(0);
    (c|C)(i|I)(o|O)/e('|`) printf("%s", yytext); BEGIN(EST);
    [cCnNsSlLmMtTvV]('|`)/e('|`) printf("%s", yytext); BEGIN(CI);
    <CI>e('|`)  printf("%s", "\x8a"); BEGIN(0);
    <CI>.  printf("%s", yytext); BEGIN(0);
    ([ \t]+|\n)/e('|`) printf("%s", yytext); BEGIN(EST);
    <EST>e('|`)   printf("%s", "\x8a"); BEGIN(0);
    <EST>.  printf("%s", yytext); BEGIN(0);
    e' printf("%s", "\x82");
    i('|`) printf("%s", "\x8d");
    o('|`) printf("%s", "\x95");
    u('|`) printf("%s", "\x97");
    . printf("%s", yytext); BEGIN(0);
    %%
    main ()
        {
            yylex();
        }
I casi particolari considerati sono, mi pare di capire, alcune
elisioni (mo', po', da', de'), i composti con 'che' (perché, finché,
ecc., per poterci mettere l'accento acuto), vari casi con 'è', e
qualche altra cosa che non capisco.
Sorprendentemente, sui messaggi FidoNet funzionava discretamente bene,
sebbene mi sia difficile dire perché funzionava quando funzionava e
perché ci scagliava quando ci scagliava. Su testi più vari, quali
quelli di cui parlavi, credo che fallirebbe molto più di frequente.
Con un po' di pazienza, qualcosa del genere (con qualche
perfezionamento) si può, naturalmente, scrivere anche in Perl.
Una strategia basata su un dizionario funzionerebbe probabilmente su
un insieme più vasto di testi, ma è più complicata e meno efficiente. 
Ciao.