Newsgroup: it.comp.lang.perl
Titolo: eliminare spazi interni a TAG

Salve a tutti,
ho la necessita' di eliminare/sostituire spazi all'interno di TAG
lasciando pero' il valore inalterato, es:
DA:
<MIO TAG CON SPAZI> Ciao Mondo</MIO TAG CON SPAZI>
A:
<MIO-TAG-CON-SPAZI> Ciao Mondo</MIO-TAG-CON-SPAZI>
Con due elementi all'interno del tag avevo risolto con questa:
$mioTag =~ s/<([\/\w\d_]+)\s([\w\d_]+)>/<$1-$2>/g;
ma non sapendo a priori di quanti elementi e' costituito il TAG, non
saprei come fare...
Ciao e grazie

 saprei come fare...
Allora... ho risolto in questo modo:
sub noSpaceTAG
     {
          my $ref = shift;
          $$ref =~ s/<([\/\w\d_\-]+)\s(.+?)>/<$1-$2>/g;
          noSpaceTAG($ref) if($$ref =~ /<([\/\w\d\_\-]+)\s(.+?)>/);
      }
my $data ="<primo secondo>
                  <altro tag>
                      <la b el>Hello World</la b el>
                  </altro tag>
              </primo secondo>";
noSpaceTAG(\$data);
Capisco che sia poco elegante, ma sembra funzionare.
Ci sono idee per migliorare la situazione??
Ciao

 Ci sono idee per migliorare la situazione??
Direi che in questo caso la ricorsione è inutile. Una cosa bella
dell'operatore s/// è che ti
restituisce il numero di sostituzioni effettuate. Nel tuo caso,
quindi, basta fare qualcosa
tipo:
   1 while $stuff =~ s/<([\/\w\d_\-]+)\s(.+?)>/<$1-$2>/g;
Ovviamente questo sostituisce ciascuno spazio con un "_", quindi
"<ciao   a   tutti>" diventa "<ciao---a---tutti>".
Se ne vuoi uno solo, basta mettere "\s+" al posto di "\s", ma questo
immagino tu lo sappia già visto che la regex
non mi sembra banalissima.
Nota inoltre che \w già comprende \d e _, anche se io cambierei
approccio prendendo *tutti* i caratteri che *non* siano spazi o il
terminatore di tag. Cambierei anche '+' in '*', tanto per essere al
sicuro da spazi all'inizio ed alla fine. Puoi inoltre utilizzare anche
delle parentesi per le varie porzioni (ed evitare di fare escape di
caratteri come /, anche se l'ho eliminato :), ed il modificatore x per
rendere tutto più leggibile. Quindi:
   1 while $stuff =~ s{
                         <            # inizio tag
                            ([^\s>]*) # primo gruppo
                            \s        # spazio da sostituire
                            (.*?)     # resto del tag (secondo gruppo)
                         >            # chiusura tag
                      }
                      {<$1-$2>}xg;    # rigenerazione tag con
sostituzione
Qui però sorge un problema: se hai un tag fatto così:
   <ciao a
       tutti>
la regex fallisce. Il '.' nel secondo gruppo, infatti, *non* matcha i
newline. Per farlo
devi utilizzare il modificatore s (perldoc perlre, all'inizio):
   1 while $stuff =~ s{
                         <            # inizio tag
                            ([^\s>]*) # primo gruppo
                            \s        # spazio da sostituire
                            (.*?)     # resto del tag (secondo gruppo)
                         >            # chiusura tag
                      }
                      {<$1-$2>}xsg;   # rigenerazione tag con
sostituzione
Ora non ti resta che provarla, mica sono sicuro che funzioni :)
Nota a latere: se usi il riferimento per evitare la copia dei dati
alla funzione, puoi avvalerti del fatto che
il passaggio dei parametri ad una funzione effettua un aliasing su @_.
Quindi:
   sub clean_up {
      # Uso $_[0] che è un alias per il primo parametro passato
      1 while $_[0] =~ s{
                           <            # inizio tag
                              ([^\s>]*) # primo gruppo
                              \s        # spazio da sostituire
                              (.*?)     # resto del tag (secondo
gruppo)
                           >            # chiusura tag
                        }
                        {<$1-$2>}xsg;   # rigenerazione tag con
sostituzione
   }
   clean_up($data); # $data viene "incarnata" da $_[0] in clean_up()
In funzioni più grandi è meglio evitare di usare direttamente @_, ed
utilizzare i riferimenti come nel
tuo caso; in funzioni così piccole, però, la comprensibilità e la
manutenibilità non ne soffrono ma
aumenta la semplicità d'uso. IMHO.

 aumenta la semplicità d'uso. IMHO.
Non credo d'aver capito bene cosa intendi...
Io volevo evitare di passare $stuff come parametro alla funzione
perche' puo' essere  anche molto corposa, quindi ho preferito
l'utilizzo di un "puntatore". Non capisco come la dimensione di una
funzione possa implicare il passaggio per parametro piuttosto che per
reference.
Ciao e grazie mille!
p.s.
Il messaggio e' stato stampato ed archiviato in mezzo al perl
cookbook :-)

 non ho provato,ma dovrebbe andare...
Anche questa soluzione e' molto furba... purtroppo non funziona...
Appena riesco a risistemarla la posto a futura memoria.
Ciao

 reference.
L'aliasing a cui mi riferivo riguarda il fatto che il passaggio di una
variabile ad una sub non implica una copia della variabile. Per
spiegarmi meglio, quando chiami:
    una_funzione($variabile_con_molti_dati);
nella sub una_funzione ti viene passato l'array @_, che contiene nella
posizione 0 un "alias" di $variabile_con_molti_dati. Non si tratta di
una copia, ma della stessa identica variabile che, nella sub, assume
un "nome" differente, ossia $_[0].
Questo vuol dire che puoi risparmiarti di passare per un reference, ed
utilizzare direttamente $_[0], senza temere di aver perso tempo e
memoria in copie inutili. Ovviamente, usare $_[0], $_[1], ecc. rischia
di compromettere la leggibilità del tuo codice, motivo per il quale
restringerei il loro utilizzo solamente a funzioni molto piccole, in
modo da evitare di essere criptici e soprattutto tenersi al sicuro da
errori (tipo scambiare gli indici, ecc.).